与业力茉莉花上的角度隔离

时间:2015-07-02 20:36:07

标签: javascript angularjs karma-jasmine

我有一组分布在两个模块中的测试。

第一个模块有测试,并且对于它的依赖,我声明模拟测试它而不受其依赖模块的任何影响,如下所示:

        beforeEach(function(){
            angular.mock.module(function ($provide) {
                $provide.value("mockServiceFromModule1", mockServiceFromModule1);
                $provide.value("mockServiceFromModule2", mockServiceFromModule2);
            });

            angular.module('module1', []);
            angular.module('module2', []);
            angular.mock.module('moduleThatIAmTesting');

            angular.mock.inject(function (_$rootScope_, _$q_, _$httpBackend_, ..., somethingFromTestModule) {

            });

    })

第二个模块有一系列测试,当我只运行它们时,所有测试都会通过。

        beforeEach(function(){

            angular.mock.module('module1');

            angular.mock.inject(function (_$rootScope_, _$q_, _$httpBackend_, ..., somethingFromModule1) {

            });

    })

使用f(仅运行它们)运行时的两个测试都有效,但是当我运行整个测试套装时,我会收到错误,特别是关于模块声明或$httpBackend

我如何使茉莉花运行每个测试,好像它们是唯一的测试一样?

我似乎在每次测试时都在使用angular / modules / $ httpBackEnd,并且在开始新测试时会传播更改。

更新1 我有jsFiddle代表问题。 问题的结构是:

  • 使用模拟依赖模块运行某些测试
  • 后来另一个测试想要测试实际的模拟模块
  • 由于第一个moldule已经加载,我们无法覆盖它,测试失败。

在JSFiddle上,关于$ httpBackend的错误没有任何要刷新的错误是因为对expectGet的请求永远不会被命中,并且由于之前加载的空模块而永远不会被命中

重要的是要注意,测试的ORDER是与JSFiddle中失败相关的唯一相关内容,并且它们通过相同的测试。

我当然可以制定一个测试命令并绕过它,但我的目标是找到一种方法来进行隔离测试,而不必担心其他测试副作用。

1 个答案:

答案 0 :(得分:1)

您遇到的问题是由于$compileProvider如何处理使用预先存在的名称注册的新指令的性质。

总之; 您没有覆盖旧指令,您正在创建具有相同名称的辅助指令。因此,原始实现会运行并尝试抓取baz.html$httpBackend抛出,因为您尚未设置该调用的期望。

查看updated fiddleoriginal fiddle做出两次更改的ng-click

  1. 请勿将parentModule注入您的childModule规范。不需要该行,这是您看到这些错误的部分原因。哦,angular.module在测试之地是邪恶。尽量不要使用它。
  2. 装饰原始指令,如果您希望使用与原始指令相同的名称滚动,或将其命名为其他内容。我已选择将其命名为其他内容在小提琴中,但我在答案的最后提供了代码,以显示装饰器方式。
  3. 以下是在以下场景中发生的事情的屏幕截图:

    • 模块 A 注册名为baz的指令。
    • 模块 B 取决于模块 A
    • 模块 B 注册名为baz的指令。

    正如您可能想象的那样,为了让模块系统不要通过让人们覆盖每个指令来实现自己的操作 - $compileProvider将只使用另一个指令 >同名。并且都将运行

    采用此article示例或此jsFiddle showing the decorator approach概述我们如何利用具有相同名称的多个指令。

    请参阅下面附带的屏幕截图,了解您的情况。 multi-dir-same-name

    71 73 行的代码是您可以实现我在答案开头提到的解决方案#2的地方。

    装饰baz

    testModule的beforeEach中,替换以下内容:

    $compileProvider.directive('baz', function () {
        return {
            restrict: 'E',
            template: '{{value}}<div ng-transclude></div>',
            controllerAs: 'bazController',
            controller: function ($scope, fooService) {
                $scope.value = 'baz' + fooService.get()
            },
            transclude: true
        };
    });
    

    有了这个:

    $provide.decorator('bazDirective', function ($delegate) {
      var dir = $delegate[0];
    
      dir.template = '{{value}}<div ng-transclude></div>';
    
      dir.controller = function ($scope, fooService) {
          $scope.value = 'baz' + fooService.get();
      };
    
      delete dir.templateUrl;
    
      return $delegate;
    });
    

    <强> angular-module

    angular.module('parent', [])的呼叫怎么样?

      

    除非您恰好使用http://jsfiddle.net/6oaxt61a/10/要点,否则不应在规范中致电angular.module('name', [])。即使这样,在测试的土地上也没有为你做太多。

    仅使用.mock.modulewindow.module,否则您终止与指定模块相关的即将推出的规范,因为您已经有效地杀死了模块定义其余的规范

    此外,bazparentModule的{​​{1}}指令定义将自动在您的testModule规范中提供,原因如下:

    angular.module('parent', []).directive('baz', fn());
    
    angular.module('child', ['parent']);
    
    // In your test: 
    
    module('child'); // Will automatically fetch the modules that 'child' depend on. 
    

    因此,即使如果我们在您的规范中删除angular.module('parent', [])调用,原始的baz定义仍将加载。

    因此,由于$compileProvider支持具有相同名称的多个指令的性质,HTTP请求飞离,这是您的规范套件失败的原因。

    另外,作为最后一点;您正在undefined块中配置beforeEach个模块。如果目标是配置测试模块,则说明错了。

    语法如下:

    mock.module('child', function ($compileProvider, /** etc **/) {
    });
    
    // Not this:
    mock.module('child'); 
    mock.module(function ($compileProvider, /** etc **/) {
    });
    

    这可以在我发布的截图中看到。被模拟的$$moduleName定义的baz属性为undefined,而我假设您希望它为child

相关问题