2016-08-11 45 views
0

我試圖在控制器中對我的狀態進行單元測試。我想要做的是剔除我的items工廠,因爲我有單獨的單元測試涵蓋了該功能。我很難讓$injector實際注入工廠,但似乎我讓$provider知道我想在實例化控制器時使用我的僞項目對象。作爲一個免責聲明,我是全新的角色,如果我的代碼看起來不好,我會喜歡一些建議。解決方案中使用的存根工廠

目前,當我運行測試我得到的消息:

Error: Unexpected request: GET /home.html 
    No more request expected 
     at $httpBackend (node_modules/angular-mocks/angular-mocks.js:1418:9) 
     at n (node_modules/angular/angular.min.js:99:53) 
     at node_modules/angular/angular.min.js:96:262 
     at node_modules/angular/angular.min.js:131:20 
     at m.$eval (node_modules/angular/angular.min.js:145:347) 
     at m.$digest (node_modules/angular/angular.min.js:142:420) 
     at Object.<anonymous> (spec/states/homeSpec.js:29:16) 

看來,我的嘲笑項目工廠沒有被注入測試。當我將console.log行放入要在工廠工廠中存根的方法中時,我看到該行將被調用。

我在尋找要測試的代碼如下:

angular.module('todo', ['ui.router']) 
// this is the factory i want to stub out... 
.factory('items', ['$http', function($http){ 
    var itemsFactory = {}; 
    itemsFactory.getAll = function() { 
    // ...specifically this method 
    }; 
    return itemsFactory; 
}]) 
.controller('TodoCtrl', ['$scope', 'items', function($scope, items) { 
    // Do things 
}]) 
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){ 
    $stateProvider 
    .state('home', { 
     url: '/home', 
     templateUrl: '/home.html', 
     controller: 'TodoCtrl', 
     resolve: { 
     items: ['items', function(items){ 
      // this is the invocation that i want to use my stubbed method 
      return items.getAll(); 
     }] 
     } 
    }); 

    $urlRouterProvider.otherwise('home'); 
}]); 

我的測試是這樣的:

describe('home state', function() { 

    var $rootScope, $state, $injector, state = 'home'; 
    var getAllStub = sinon.stub(); 
    var items = { 
    getAll: getAllStub 
    }; 

    beforeEach(function() { 
    module('todo', function($provide) { 
     $provide.value('items', items); 
    }); 

    inject(function(_$rootScope_, _$state_, _$injector_) { 
     $rootScope = _$rootScope_; 
     $state = _$state_; 
     $injector = _$injector_; 
    }); 
    }); 

    it('should resolve items', function() { 
    getAllStub.returns('getAll'); 

    $state.go(state); 
    $rootScope.$digest(); 
    expect($state.current.name).toBe(state); 

    expect($injector.invoke($state.current.resolve.items)).toBe('findAll'); 
    }); 
}); 

預先感謝您的幫助!

+0

你嘲笑的工廠很好。由於請求了「/home.html」模板,因此出現錯誤。在單元測試中允許真正的路由器是一個壞主意,因爲它打破了隔離並增加了更多移動部分。我個人認爲'$ stateProvider'等存根更好的測試策略。您只需確保使用期望的配置對象作爲參數調用'$ stateProvider.state'。如有必要,應用程序可以在集成/ e2e測試中使用真正的路由器進行測試。 – estus

+0

我喜歡這個建議。我嘗試用'items'方式去掉'$ stateProvider'和$ $ urlRouterProvider',但不幸的是我仍然看到與上面相同的錯誤 – davidicus

+0

我發佈了一個解釋這個問題的答案。注意,在這種情況下你不需要用'$ state.go'來測試它(並且在這個規範中根本沒有'$ state'服務)。 – estus

回答

0

在單元測試中允許真正的路由器是一個壞主意,因爲它打破了隔離並增加了更多的移動部分。我個人認爲$stateProvider等stubs更好的測試策略。

命令在配置塊中很重要,服務提供者在被注入其他模塊之前應該被嘲笑。如果原來的模塊有config塊是覆蓋嘲笑服務商,模塊應存根:

beforeAll(function() { 
    angular.module('ui.router', []); 
    }); 

    beforeEach(function() { 
    var $stateProviderMock = { 
     state: sinon.stub().returnsThis() 
    }; 

    module(function($provide) { 
     $provide.constant('$stateProvider', $stateProviderMock); 
    }); 
    module('todo'); 
    }); 

你只需要確保$stateProvider.state調用與預期的配置對象的參數:

it('should define home state', function() { 
    expect($stateProviderMock.state.callCount).to.equal(1); 

    let [homeStateName, homeStateObj] = $stateProviderMock.state.getCall(0).args; 

    expect(homeStateName).to.equal('home'); 
    expect(homeState).to.be.an('object'); 

    expect(homeState.resolve).to.be.an('object'); 
    expect(homeState.resolve.items).to.be.an('array'); 

    let resolvedItems = $injector.invoke(homeState.resolve.items); 
    expect(items.getAll).to.have.been.calledOnce; 
    expect(resolvedItems).to.equal('getAll'); 

    ... 
    }); 
+0

感謝您的回覆!儘管如此,我仍然對單元測試的入口點感到困惑。以前我使用'$ rootScope。$ digest()'來啓動解決方案,但在這裏我不確定我要寫入哪條線來執行狀態。 – davidicus

+0

這是實際的規格,解析器通過'$ injector.invoke'進行檢查,然後您可以觸發摘要f解析器包含取決於摘要的代碼。你不需要在這裏執行狀態,只是用'$ stateProvider'檢查狀態是否正確定義。 「$ state.go('home')'將狀態更改爲'home'這一事實已經由UI Router進行了測試!如果您還需要確保設備正常工作並且沒有意外,這是整合/ e2e量角器測試的一項任務。 – estus

+0

明白了。最後一件事,當我嘗試運行測試時,我在第一行expect($ stateProviderMock.state.callCount).to得到一個錯誤。等於(1);'因爲callCount仍然爲零 – davidicus

相關問題