在 AngularJS 单元测试中模拟模块依赖

Posted

技术标签:

【中文标题】在 AngularJS 单元测试中模拟模块依赖【英文标题】:Mocking module dependencies in AngularJS unit tests 【发布时间】:2017-09-25 15:12:43 【问题描述】:

我有一个 Angular 1.5 项目,其中包含许多模块,每个模块可能依赖于其他模块。尝试对作为模块一部分的控制器进行单元测试时,我会像这样导入模块:

angular.mock.module('SaidModule');

...然后在需要的地方提供并注入它的服务。

问题在于SaidModule 依赖于AnotherModule1AnotherModule2AnotherModule3....

angular.module('SaidModule', ['AnotherModule1', 'AnotherModule2', 'AnotherModule3']);

所以很自然,当我调用 SaidModule 时,其他模块也会被调用,这超出了单元测试的范围

在单元测试中我尝试了以下解决方案

angular.module('AnotherModule1',[]);
angular.module('AnotherModule2',[]);
angular.module('AnotherModule3',[]);
angular.mock.module('SaidModule');

虽然对于当前的单元测试,我已经成功解耦了依赖关系,但我也销毁了 实际的 AnotherModule1、AnotherModule2、AnotherModule3 所以当轮到它进行单元测试时,它们是 在我看来正确的角度项目中甚至都看不到。因为我使用 angular.module 来定义一个 恰好覆盖实际模块的新模块。 不过,这里也建议使用此解决方案模拟模块依赖项

在 Angular 文档中,它指出请参阅 Angular 文档模拟模块 如果传递了一个对象文字,每个键值对将通过 $provide.value 在模块上注册, 键是与注入器上的值相关联的字符串名称(或标记)。

所以在我看来,解决方案以某种方式使用 angular.mock.module 以某种方式覆盖依赖项 模块,但到目前为止我还没有找到解决方案。 非常感谢任何帮助

【问题讨论】:

【参考方案1】:

通过调用angular.module('AnotherModule1',[]),您正在重新定义AnotherModule1,我认为这会导致您的下游问题。相反,为每个依赖服务使用$provide。无需模拟依赖模块。

假设您的控制器定义如下所示:

angular
  .module('SaidModule', ['AnotherModule1', 'AnotherModule2'])
  .controller('SaidController', [
    '$scope', 
    'AnotherService', 
    function($scope, AnotherService) 
      this.anotherService = AnotherService.helper();
    
  );

那么您的测试可能如下所示:

describe('SaidController', function() 
  var controller, scope, AnotherService;

  beforeEach(module('SaidModule'));

  beforeEach(module(function($provide) 
    AnotherService =  helper: function()  return 0;  ;
    $provide.value('AnotherService', AnotherService);
  ));

  beforeEach(inject(function($controller, $rootScope) 
    scope = $rootScope.$new();
    controller = $controller('SaidController', 
      $scope: scope
    );
  ));

  it('creates controller', function() 
    expect(controller).not.toBeNull();
  );
);

无需模拟依赖模块,只需模拟依赖服务。

【讨论】:

虽然这似乎不起作用,但我不确定它的正确方法,因为当模块在这里运行时 beforeEach(angular.mock.module('SaidModule'));它会加载它的依赖模块,然后我会存根它们或之后的任何东西。我真正想做的是在我以某种方式调用 angular.mock.module 阶段时阻止它们被加载 也许这篇文章回答了你的问题:***.com/questions/17554727/… 感谢您的回复@mikwat,但我不同意上述解决方案。原因是当你测试一个单元时,你不应该关心外部世界发生了什么,但在这种情况下,他正在引入模块,为了不运行它的代码,他正在对它的所有服务和方法进行存根。如果你只有 1 个依赖的模块,它可能是一个临时解决方案,但我有 5 个依赖模块,因为该项目非常复杂,所以我不可能/毫无价值地去存根其他模块正在使用的每一个服务 我想不出任何方法来避免使用 javascript 或任何其他语言对依赖的服务和方法进行存根处理。 我想你误解了我的问题。服务和方法需要存根我完全同意,但我面临的问题是模块依赖关系,我找不到存根方法。例如,模块 A 依赖于模块 B 和 C,因此当我在单元测试中实例化模块 A 时,它自然也会运行模块 B 和 C。我相信解决方案是以某种方式使用 angular.mock.module “如果传递了一个对象文字,每个键值对将通过 $provide.value 在模块上注册,键是与喷油器上的值。”

以上是关于在 AngularJS 单元测试中模拟模块依赖的主要内容,如果未能解决你的问题,请参考以下文章

在AngularJS单元测试中模拟模块依赖性

如何在 RequireJS 中模拟单元测试的依赖项?

如何使用 ES6 模块模拟单元测试的依赖关系

在 AngularJS 单元测试中模拟 $modal

如何在 AngularJS 单元测试中模拟 $window.location.replace?

如何模拟在 AngularJS Jasmine 单元测试中返回承诺的服务?