将模拟注入到 AngularJS 服务中

我有一个编写的AngularJS服务,我想对其进行单元测试。

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

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

    return this;
});

我的应用.js文件已注册以下文件:

angular
.module('myApp', ['fooServiceProvider','barServiceProvider','myServiceProvider']
)

我可以测试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();
    });
});

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

我该怎么做?

我尝试过将我的模拟对象放在模块中,例如

beforeEach(module(mockNavigationService));

并将服务定义重写为:

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

但后者似乎阻止了DI创建的服务。

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

谢谢

大卫


答案 1

您可以使用 将模拟注入到服务中。$provide

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

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

您可以注入 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');
  }));

});

请注意,由于调用您,实际上不需要在任何地方显式注入 myDependency。它发生在注入myService期间。在这里设置模拟独立性时,它很容易成为间谍。$provide.value

感谢忠诚的Brown链接到那个伟大的视频


答案 2

在我看来,没有必要嘲笑服务本身。只需模拟服务上的函数即可。这样,您就可以像在整个应用程序中一样,让angular注入您的真实服务。然后,根据需要使用 Jasmine 的函数模拟服务上的函数。spyOn

现在,如果服务本身是一个函数,而不是一个你可以使用的对象,那么还有另一种方法可以做到这一点。我需要这样做,并找到了一些对我来说很有效的东西。请参阅如何模拟作为函数的 Angular 服务?spyOn