将模拟注入AngularJS服务

Ban*_*San 114 javascript mocking jasmine angularjs angularjs-service

我写了一个AngularJS服务,我想对它进行单元测试.

angular.module('myServiceProvider', ['fooServiceProvider', 'barServiceProvider']).
    factory('myService', function ($http, fooService, barService) {

    this.something = function() {
        // Do something with the injected services
    };

    return this;
});
Run Code Online (Sandbox Code Playgroud)

我的app.js文件已注册:

angular
.module('myApp', ['fooServiceProvider','barServiceProvider','myServiceProvider']
)
Run Code Online (Sandbox Code Playgroud)

我可以测试DI是这样工作的:

describe("Using the DI framework", function() {
    beforeEach(module('fooServiceProvider'));
    beforeEach(module('barServiceProvider'));
    beforeEach(module('myServiceProvder'));

    var service;

    beforeEach(inject(function(fooService, barService, myService) {
        service=myService;
    }));

    it("can be instantiated", function() {
        expect(service).not.toBeNull();
    });
});
Run Code Online (Sandbox Code Playgroud)

这证明了服务可以由DI框架创建,但是接下来我想对服务进行单元测试,这意味着模拟注入的对象.

我该怎么做呢?

我已经尝试将模拟对象放在模块中,例如

beforeEach(module(mockNavigationService));
Run Code Online (Sandbox Code Playgroud)

并将服务定义重写为:

function MyService(http, fooService, barService) {
    this.somthing = function() {
        // Do something with the injected services
    };
});

angular.module('myServiceProvider', ['fooServiceProvider', 'barServiceProvider']).
    factory('myService', function ($http, fooService, barService) { return new MyService($http, fooService, barService); })
Run Code Online (Sandbox Code Playgroud)

但后者似乎停止了由DI创建的服务.

有人知道如何模拟我的单元测试的注入服务吗?

谢谢

大卫

Joh*_*bos 182

您可以使用以下方法将嘲笑注入您的服务$provide.

如果您具有以下服务,其依赖项具有名为getSomething的方法:

angular.module('myModule', [])
  .factory('myService', function (myDependency) {
        return {
            useDependency: function () {
                return myDependency.getSomething();
            }
        };
  });
Run Code Online (Sandbox Code Playgroud)

您可以注入myDependency的模拟版本,如下所示:

describe('Service: myService', function () {

  var mockDependency;

  beforeEach(module('myModule'));

  beforeEach(function () {

      mockDependency = {
          getSomething: function () {
              return 'mockReturnValue';
          }
      };

      module(function ($provide) {
          $provide.value('myDependency', mockDependency);
      });

  });

  it('should return value from mock dependency', inject(function (myService) {
      expect(myService.useDependency()).toBe('mockReturnValue');
  }));

});
Run Code Online (Sandbox Code Playgroud)

请注意,由于对$provide.value您的调用实际上不需要在任何地方显式地注入myDependency.它在我的服务注入期间发生在引擎盖下.在这里设置mockDependency时,它可能很容易成为间谍.

感谢loyalBrown链接到那个精彩的视频.

  • 工作得很好,但要注意一个细节:`beforeEach(模块('myModule'));`call**HAS**来到`beforeEach(function(){MOCKING})`调用之前,否则模拟将获得被真实服务覆盖! (13认同)
  • 如果你的模拟需要$ q怎么办?然后你不能在调用module()之前将$ q注入模拟器以注册模拟.有什么想法吗? (7认同)
  • 类似于Nikos的评论,任何``$ provide```调用必须在使用```$ inject```之前进行,否则你会收到一个错误:```Injector已经创建,无法注册模块!``` (5认同)
  • 如果你正在使用coffeescript并且你看到`错误:[ng:areq] Argument'fn'不是函数,得到了Object`,请确保在`$ provide.value之后在行上放置`return`( ...)`.隐式返回`$ provide.value(...)`给我造成了这个错误. (4认同)