2014-07-16 72 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