在 angular 业力测试中监视有线服务

Spying on a wired service in angular karma test

是否可以在由 Angular 连接的业力测试中监视服务?

示例:myService 是被测单元。 thirdParty 代表应该被监视的第三方服务。

.service('thirdParty', function() {
    return {
        hello: function() {
            return 'hello world';
        }
    }
})
.service('myService', function(thirdParty) {
    return {
        world: function() {
            return thirdParty.hello();
        }
    }
})

在我的业力测试中,我想监视 thirdParty 服务并调用真正的服务:

describe('spy', function() {
    var thirdParty, myService;

    beforeEach(inject(function(_thirdParty_, _myService_) {
        myService = _myService_;
        thirdParty = _thirdParty_;

        spyOn(thirdParty, 'hello').andCallThrough();
    }));

    it('should be called in myService', function() {
        expect(thirdParty.hello).toHaveBeenCalled();
        expect(myService.world()).toBe('hello world');
    });
})

重点是我的测试应该断言

  1. 内部调用了第三方服务的具体方法myService
  2. 第三方服务不会更改会导致异常或意外结果的内部行为(例如,在库更新后)

myService.world() 断言有效,但正如我所料,myService 并未在间谍 thirdParty 服务上运行。

结果是:

Expected spy hello to have been called.

在某些测试中,我已经使用 provider 和裸模拟来模拟第三方服务。 所以我试图创建一个 cacheFactory 的间谍实例,它附带 angular-cache:

beforeEach(module('angular-cache'));

beforeEach(module(function($provide, $injector, CacheFactoryProvider) {
    //CacheFactoryProvider requires $q service
    var q = $injector.get('$q');
    var cacheFactory = CacheFactoryProvider.$get[1](q);

    spyOn(cacheFactory, 'createCache').andCallThrough();
    $provide.factory('CacheFactory', cacheFactory);
}));

现在我面临先有鸡还是先有蛋的问题:

Error: [$injector:modulerr] Failed to instantiate module function ($provide, $injector, CacheFactoryProvider) due to:
Error: [$injector:unpr] Unknown provider: $q

我知道这个例子行不通,但由于缺乏内部知识 Angular 实际上是如何实例化和连接服务的,我想问问社区我的测试方法是否可行,甚至理智的。感谢您的帮助。

而不是

it('should be called in myService', function() {
    expect(thirdParty.hello).toHaveBeenCalled();
    expect(myService.world()).toBe('hello world');
});

测试应该是

it('should be called in myService', function() {
    expect(myService.world()).toBe('hello world');
    expect(thirdParty.hello).toHaveBeenCalled();
});

确实,在您实际调用 myService.world() 之前,thirdParty.hello 方法不会被调用。