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

时间:2016-10-21 15:50:24

标签: javascript angularjs unit-testing jasmine

我正在尝试对Angular服务进行单元测试,该服务使用$ injector注入另一个服务,而不是将服务依赖项作为参数传递。注入的服务是动态的 - 它可能是许多不同服务之一 - 因此它不能作为函数参数传递。

正在测试的服务确定应用程序是在线还是离线,然后使用策略模式进行HTTP调用(我们在线,因此策略是“远程”)或使用本地存储来获取所需数据(我们离线,所以策略是'本地')。它在整个应用程序中的许多场景中使用,因此随后调用的服务和服务方法是动态的。更容易显示简化的相关代码:

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

}

我的问题是,因为我无法在单元测试中以正常方式注入服务,所以我不知道如何测试这段代码。我已经模拟了配置,现在我想测试在线和离线时调用正确的服务方法,例如:

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

如何确保模拟服务 服务,并将其传递到我的测试服务中?

1 个答案:

答案 0 :(得分:0)

好的,我好像已经解决了它:

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