简体   繁体   English

Angular单元测试,模拟使用$ injector注入的服务

[英]Angular unit tests, mocking a service that is injected using $injector

I'm trying to unit test an Angular service, that has another service injected into it using $injector, rather than passing the service dependency as an argument. 我正在尝试对Angular服务进行单元测试,该服务使用$ injector将另一个服务注入其中,而不是将服务依赖项作为参数传递。 The injected service is dynamic - it could be one of a number of different services - and so it can't be passed as a function argument. 注入的服务是动态的 - 它可能是许多不同服务之一 - 因此它不能作为函数参数传递。

The service under test determines if the application is online or offline, then uses the strategy pattern to either make an HTTP call (we're online, so the strategy is 'remote') or use local storage to get the required data (we're offline, so the strategy is 'local'). 被测服务确定应用程序是在线还是离线,然后使用策略模式进行HTTP调用(我们在线,因此策略是“远程”)或使用本地存储来获取所需数据(我们'重新离线,所以策略是“本地的”)。 It's used in a number of scenarios across the application, so the service and the service method that is subsequently called are dynamic. 它在整个应用程序中的许多场景中使用,因此随后调用的服务和服务方法是动态的。 Easier to show the simplified, relevant, code: 更容易显示简化的相关代码:

class NetworkStrategyService {
    constructor (private Offline, private $injector) {}

    fulfill (config) {
        this.Offline.check()
            .then(
                () => {
                    // we're online
                    const service = $injector.get(config.remote.service);
                    service[config.remote.method](config.remote.data)
                        .then(() => {
                            // Do something with the data
                        })
                },
                () => {
                    // Grab it from local storage
                }
            )
    }

}

My problem is, because I can't inject the service in the normal way in my unit tests, I don't know how to test this code. 我的问题是,因为我不能在我的单元测试中以正常方式注入服务,我不知道如何测试这段代码。 I've mocked the config, now I want to test that the correct service methods are being called while online and offline, such as: 我已经模拟了配置,现在我想测试在线和离线时调用正确的服务方法,例如:

it (`calls the remote service, with the remote method, if we're online`, () => {
    const remoteMethod = spyOn(config.remote.service, config.remote.method);
    // Set up, to get a successful Offline.check() outcome
    expect(remoteMethod).toHaveBeenCalledWith(config.remote.data);
});

How can I ensure that the mocked service is a service, and pass it into my service under test? 如何确保模拟服务一项服务,并将其传递给我的测试服务?

OK, I seem to have solved it: 好的,我好像已经解决了它:

let deferred;
let config = {
    remote: {
        service: 'RemoteService',
        method: 'remoteAction',
        data: {alpha:1}
    },
    local: ...
};

beforeEach(() => {
    angular.mock.module(($provide) => {
        $provide.service(config.remote.service, () => {
            return {
                [config.remote.method]: () => {}
            };
        });
    });
});

beforeEach(() => {
    inject((_$q_, _$rootScope_, _$injector_) => {
        $q = _$q_;
        $scope = _$rootScope_.$new();
        $injector = _$injector_
    });
    deferred = $q.defer();
});

beforeEach(() => serviceUnderTest = new NetworkStrategyService(Offline, $injector));

it (`calls the remote service, with the remote method, if we're online`, () => {
    let dynamicService;
    inject((_RemoteService_) => {
        dynamicService = _RemoteService_;
    });
    serviceUnderTest.strategy = 'remote';
    const dynamicMethod = spyOn(dynamicService, config.remote.method).and.returnValue(deferred.promise);
    serviceUnderTest.makeCall(config);
    deferred.resolve();
    $scope.$apply();
    expect(dynamicMethod).toHaveBeenCalledWith(config.remote.data);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM