真正嘲笑提供者

时间:2015-06-25 10:15:06

标签: angularjs unit-testing

所以基本上没有关于如何在模块上省略配置/运行/提供程序块而没有为单元测试做一些文件加载​​排序黑客的信息。假设如下:

// 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
  }]);

现在假设我们正在为controller编写单元测试。我们该怎么做?

module('module1');
inject(function ($controller, $rootScope) {
  ...
});
哎呀,我们遇到了问题。 module('module1')将触发ccc的提供商定义,该定义依赖于bbb,依赖于aaa。因此,除非我们阻止在ccc上触发module1的提供商定义,否则我们将运行与我们进行单元测试的controller无关的代码。

我们可以使用bbb表示法来模拟module(function ($provide) { ... });,这样我们就不需要加载module0

但这并没有为ccc解决这个问题。我没办法阻止它跑。

问题:有没有办法阻止module1运行ccc提供商的定义,这与controller无关我们是单位测试?

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

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

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

1 个答案:

答案 0 :(得分:2)

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

module1internal - 此模块不具有依赖关系,将用于所有模块 您的应用程序提供商

angular.module('module1internal', []);

module1 - 此模块依赖于module1internal并将包含所有其他依赖项,config和run block

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;
  }

});