2014-07-16 99 views
14

我想知道應該如何測試與Karular測試與Angular.js + UI路由器?Karma測試與Angular.js + UI路由器

我有以下狀態定義:它有兩個解決方案,獲取一些數據併爲控制器準備數據。 (從灰燼背景的,這使得有很大的意義。)

$stateProvider 
    .state('users', { 
    resolve: { 
     getData: function (User) { 
     return User.query().$promise 
     }, 
     stateModels: function (getData) { 
     var models = {} 
     models.users = getData 
     return models 
     } 
    }, 
    url: '/', 
    templateUrl: '/views/users/index.html', 
    controller: 'UsersIndexCtrl' 
    }) 

我們UserIndexCtrl樣子:(更是把解決stateModels,並將其分配給$範圍,所以認爲可以用它)

app.controller('UsersIndexCtrl', [ 
    '$scope', '$state', 'stateModels', 
    function ($scope, $state, stateModels) { 

    $scope.users = stateModels.users 

    }]) 

這是在瀏覽器中運行良好,我看到了正確的結果。但是,當涉及到測試時,它給了我奇怪的錯誤。

下面是一個例子噶單元測試:

describe('controllers', function() { 

    var $httpBackend 
    , $rootScope 
    , $scope 
    , $state 
    , $httpBackend 
    , $controller 

    beforeEach(module('app')) 

    beforeEach(inject(function ($injector) { 
    $state = $injector.get('$state') 
    $rootScope = $injector.get('$rootScope') 
    $httpBackend = $injector.get('$httpBackend') 
    $scope = $rootScope.$new() 
    $controller = $injector.get('$controller') 
    })) 

    it('UserIndexCtrl should exist', inject(function() { 
    $httpBackend 
     .expect('GET', '/api/users') 
     .respond(200, {users: [ {}, {}, {} ]}) 

    $state.go('users') 
    $rootScope.$apply() 

    $controller('AdminZonesIndexCtrl', { $scope: $scope, $state: $state }); 
    $rootScope.$apply() 
    assert.equal($scope.users.length, 3) 
    })) 

}) 

而且我看到:

[$injector:unpr] Unknown provider: stateModelsProvider <- stateModels 
http://errors.angularjs.org/1.3.0-build.2937+sha.4adc44a/$injector/unpr?p0=stateModelsProvider%20%3C-%20stateModels 
Error: [$injector:unpr] Unknown provider: stateModelsProvider <- stateModels 
http://errors.angularjs.org/1.3.0-build.2937+sha.4adc44a/$injector/unpr?p0=stateModelsProvider%20%3C-%20stateModels 

這裏的想法是:

  • 我們模擬出的API請求,以致GET請求/ api /用戶將返回一個由3個對象組成的數組。我們期待看到$ scope.users應該是一個由3個對象組成的數組。
  • 從這個測試中,我們測試了在路由器中定義的兩個解決方案,並且控制器正確地分配了解析對象。

感謝

比爾

回答

26

原因你的錯誤是,你是第一個過渡到一個新的作用域實例您UsersIndexCtrl的狀態,但隨後又創建控制器(的另一個實例,與一個新的範圍)在測試中。這兩者彼此獨立,在第二種情況下,stateModels是未知/不可用依賴項。因此,雖然您的想法是有效的測試問題,但試圖將所有三者置於一起時,您基本上都會在單元測試環境中執行端到端測試。你不應該想 - 這樣就會產生一個脆弱的依賴:

  • 屬於「用戶」狀態
  • ,在狀態轉變某處特定的HTTP請求被稱爲
  • ,該控制器stateModels依賴關係綁定到作用域。

在這些斷言中,只有最後一個是控制器所關心的。您的控制器的單元測試不會保護如何/何時實例化或何時stateModels依賴來自它們,它們只關心控制器自身的行爲。所以,讓我們起來的拆分此行爲:

單元測試控制器

你的第一次測試應減少到以下幾點:

it('binds the users to the scope', function(){ 
    var stateModels = [{}, {}, {}]; 
    $controller('UserIndexCtrl', {$scope: $scope, stateModels: stateModels}); 
    assert.equal($scope.users, stateModels); 
}); 

注意,當您添加更多的測試,你可能會想要將您的控制器實例化爲beforeEach塊。

測試路線

測試路線的擔憂是真的的應用行爲,你應該推遲到Protractor。但是,如果您特別想對某個狀態執行單元測試,則可以通過測試狀態本身的配置來實現這一點。例如:

it('resolves the stateModels dependency', function() { 
    var state = $state.get('users'); 
    assert.isDefined(state.resolve.stateModels); 
    // perform assertion that stateModels function resolves to what is expected 
    // Note: any such assertion should stub any dependency being used, to ensure 
    // we are testing in isolation. 
}); 

儘管如此,我個人不選單元測試路由/路由配置,並通過與量角器端對端測試,而不是獲得這樣的報道。

+0

這很好地總結了我的問題。 – Bill

+0

@scarlz,我是mocha-Chai的新手,你能幫我解決類似的問題嗎?http://stackoverflow.com/questions/28606056/mocha-chai-test-case-for-angular-configuration-file – mayank

+0

這幾乎總結了我的生活。 – Igor