Angularjs 真正的嘲笑提供者

Angularjs 真正的嘲笑提供者,angularjs,unit-testing,Angularjs,Unit Testing,因此,基本上没有关于如何省略模块上的config/run/provider块而不进行单元测试的文件加载排序的信息。假设如下: // dependency chain for providers: // aaa <- bbb <- ccc angular.module('module0').provider('bbb', [ 'aaaProvider', function (aaaProvider) { // aaaProvider definition

因此,基本上没有关于如何省略模块上的config/run/provider块而不进行单元测试的文件加载排序的信息。假设如下:

// dependency chain for providers:
// aaa <- bbb <- ccc


angular.module('module0').provider('bbb', [
  'aaaProvider', 
  function (aaaProvider) {
    // aaaProvider definition
    ...
  });

angular.module('module1').provider('ccc', [
  'bbbProvider',
  function (bbbProvider) {
    // bbbProvider definition
    ...
  });

angular.module('module1').controller('controller', [
  function () {
    // controller definition
  }]);
哎呀,我们有个问题<代码>模块('module1')将触发对
ccc
的提供者定义,该定义依赖于
bbb
,该定义依赖于
aaa
。因此,除非我们阻止
ccc
的提供者定义在
module1
上触发,否则我们将运行与
控制器无关的代码,我们正在进行单元测试

我们可以使用
模块(函数($provide){…})模拟
bbb
符号,这样我们根本不需要加载
module0

但这并不能解决
ccc
的问题。我没办法阻止它跑

问题:是否有办法阻止
module1
运行
ccc
提供程序的定义,该定义与
controller
无关,我们正在进行单元测试

到目前为止我已经尝试过的事情:

  • 覆盖单元测试中的定义:

    angular.module('module1').provider('ccc',[function(){}])


首先,您需要在app.js中创建两个模块

模块1内部-此模块没有依赖项,将用于所有 您的应用程序提供商

angular.module('module1internal', []);
模块1-此模块依赖于模块1内部,并将包括所有其他依赖项、配置和运行块

angular.module('module1', ['module1internal','bbbProvider']);
例如,在应用程序中,您应该只使用内部模块,而不是

angular.module('module1').controller('controller', [
  function () {
    // controller definition
  }]);
你应该使用

angular.module('module1internal').controller('controller', [
      function () {
        // controller definition
      }]);
测试将如下所示:

'use strict';

describe('Controller: TheController', function () {

  // mock second level dependencies
  beforeEach(function () {
    module('module1internal');
    module({
      bbb: {}
    });
  });

  var TheController, scope,
    cccMock;

  // mock injected providers
  beforeEach(inject(function (_ccc_) {
    cccMock = mock(_ccc_);
  }));


  // Initialise the controller and mock scope 
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    TheController = $controller('TheController', {
      $scope: scope
    });

  }));

  it(' should call ccc functionA on functionThatUsesFunctionA call', function () {
    TheController.functionThatUsesFunctionA("someValue");
    expect(cccMock.functionA).toHaveBeenCalledWith("someValue");
  });



  //create spy on all provider's methods(mock it)
  function mock(angularServiceToMock) {

    for (var i = 0; i < Object.getOwnPropertyNames(angularServiceToMock).length; i++) {
      spyOn(angularServiceToMock, Object.getOwnPropertyNames(angularServiceToMock)[i]);
    }
    return angularServiceToMock;
  }

});
“严格使用”;
描述('Controller:TheController',函数(){
//模拟二级依赖项
beforeach(函数(){
模块(“模块1内部”);
模块({
bbb:{}
});
});
var控制器,范围,
cccMock;
//模拟注入提供者
每次之前(注入(函数){
cccMock=模拟(ccc);
}));
//初始化控制器和模拟范围
beforeach(注入函数($controller,$rootScope){
scope=$rootScope.$new();
控制器=$controller('TheController'{
$scope:scope
});
}));
它('should call ccc function on function that usesfunction a call',function(){
使用函数A(“someValue”)的控制器函数;
期望(cccMock.functa).已被调用(“someValue”);
});
//在所有提供程序的方法上创建间谍(模拟)
功能模拟(angularServiceToMock){
对于(var i=0;i
这是一个可行的解决方案,尽管这对我来说意味着大量的重构(这是一个拥有数百个控制器、指令、提供程序运行块等的大型应用程序)。这是一个针对新项目的最佳实践建议。嗯,因此,这个问题得到回答已经过去了一段时间。使用这种方法,如何在不运行模块中的其他提供程序的情况下对模块内部的各个提供程序进行单元测试?我不确定我是否理解这个问题,在这种方法中,有两种方法可以防止提供程序在测试中运行。1) 通过将所有公共方法转换为spy对象(示例中的函数mock())来禁用它们2)通过将提供程序添加到模块(示例中的bbb{})来覆盖提供程序,第二种方法在您要阻止运行的init onload时很有用,如果我们在一个模块中放入数千个提供者,并且只想测试1个,那么在不显式禁用999个其他提供者的情况下,我们该如何做呢?
'use strict';

describe('Controller: TheController', function () {

  // mock second level dependencies
  beforeEach(function () {
    module('module1internal');
    module({
      bbb: {}
    });
  });

  var TheController, scope,
    cccMock;

  // mock injected providers
  beforeEach(inject(function (_ccc_) {
    cccMock = mock(_ccc_);
  }));


  // Initialise the controller and mock scope 
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    TheController = $controller('TheController', {
      $scope: scope
    });

  }));

  it(' should call ccc functionA on functionThatUsesFunctionA call', function () {
    TheController.functionThatUsesFunctionA("someValue");
    expect(cccMock.functionA).toHaveBeenCalledWith("someValue");
  });



  //create spy on all provider's methods(mock it)
  function mock(angularServiceToMock) {

    for (var i = 0; i < Object.getOwnPropertyNames(angularServiceToMock).length; i++) {
      spyOn(angularServiceToMock, Object.getOwnPropertyNames(angularServiceToMock)[i]);
    }
    return angularServiceToMock;
  }

});