2017-05-08 42 views
2

我已經具有以下功能

injectService(serviceToInject: string, methodToInvoke: string){ 
    let service = this.$injector.get(serviceToInject); 
    service[methodToInvoke](); 
} 

我不知道我怎麼會測試這個服務?我試過這個:

(function() { 
'use strict'; 

describe.only('ServiceA tests', function() { 
    let ServiceA; 

    beforeEach(angular.mock.module('main')); 

    beforeEach(inject(function (_ ServiceA_, _$injector_) { 
     ServiceA = _ServiceA_; 
     $injector = _$injector_; 
    })); 

    describe.only('injectServiceAndInvoke', function() { 
     it('given a string serviceToInject which is a valid service name and a string methodToInvoke which is valid method name without parameters, it should inject the service and call the method',() => { 

      let serviceName = 'validServiceName'; 
      let methodWithoutParams = 'method'; 
      let injectedService = $injector.get(serviceName); 
      // sandboxSinon.stub(ButtonService.$injector, 'get').withArgs(serviceName).returns(stubbedService); 

      let methodToBeCalled = sandboxSinon.stub(injectedService, methodWithoutParams).withArgs(undefined); 


      sandboxSinon.stub(ServiceA, 'tokenizeState').withArgs(methodWithoutParams).returns([methodWithoutParams, undefined]); 
      ServiceA.injectServiceAndInvoke(serviceName, methodWithoutParams); 
      expect(methodToBeCalled.calledOnce).to.equal(true); 
     }); 

    }); 

}); 

})(); 

而我得到錯誤(正確),該服務'validServiceName'不存在。我也嘗試存根$ injector.get,但我不明白什麼應該返回這個存根,以及如何從這個服務調用該方法。

+0

請提供更多的測試代碼,所以答案可能會考慮到它。 – estus

+0

更新了測試 – geo

+0

順便說一句,這感覺非常像服務定位器。爲什麼你需要這樣做,你是在測試你的實現還是你正在測試框架? –

回答

3

由於$injector服務全球使用,它不能完全通過DI模擬。這是真正隔離單元測試的障礙。但是不是真的,因爲一個條件模擬壞事不使測試脆弱:

const injectedService = { methodName: sinon.stub() }; 
sinon.stub($injector, 'get'); 
$injector.get.withArgs('injectedServiceName').returns(injectedService) 
$injector.get.callThrough(); 
ServiceA.injectServiceAndInvoke('injectedServiceName', 'methodName'); 

expect($injector.get.withArgs('injectedServiceName').calledOnce).to.equal(true); 
expect(injectedService.methodName.calledOnce).to.equal(true); 
expect(injectedService.methodName.calledWith()).to.equal(true); 

但由於服務具有$injector作爲一個屬性,這爲測試一個很好的選擇,因爲物業後可以嘲笑服務實例而不是嘲弄實際$injector.get

const injectedService = { methodName: sinon.stub() }; 
const injectorMock = { get: sinon.stub() }; 
injectorMock.get.withArgs('injectedServiceName').returns(injectedService); 
ServiceA.$injector = injectorMock; 
ServiceA.injectServiceAndInvoke('injectedServiceName', 'methodName'); 

expect(injectorMock.get.withArgs('injectedServiceName').calledOnce).to.equal(true); 
expect(injectedService.methodName.calledOnce).to.equal(true); 
expect(injectedService.methodName.calledWith()).to.equal(true); 
+0

非常好的解釋。謝謝 – geo

+0

不客氣。 – estus

相關問題