[英]Karma Testing with Angular.js + UI Router
I was wondering how should one test with Karma test with Angular.js + UI router? 我想知道如何使用Angular.js + UI路由器进行Karma测试?
I have the following state defined: Which has two resolves that fetches some data and prepares the data for the controller. 我定义了以下状态:哪个有两个解析器来获取一些数据并为控制器准备数据。 (Coming from Ember background, this makes a lot of sense.) (来自Ember背景,这很有道理。)
$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'
})
Our UserIndexCtrl looks like: (Which takes the resolved stateModels and assigns it to the $scope, so the view can use it) 我们的UserIndexCtrl看起来像:(它接受已解析的stateModels并将其分配给$ scope,因此视图可以使用它)
app.controller('UsersIndexCtrl', [
'$scope', '$state', 'stateModels',
function ($scope, $state, stateModels) {
$scope.users = stateModels.users
}])
This is working great in the browser, I am seeing the right results. 这在浏览器中运行良好,我看到了正确的结果。 However, when it comes to testing it is giving me odd errors. 但是,当涉及到测试时,它给了我奇怪的错误。
Here is an example Karma unit test: 以下是Karma单元测试的示例:
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)
}))
})
And I am seeing: 而且我看到:
[$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
The idea here is: 这里的想法是:
Thanks Bill 谢谢比尔
The reason for your error is that you are first transitioning to a state which instantiates your UsersIndexCtrl
with a new scope, but then subsequently creating another instance of the controller (again, with a new scope) within the test. 出现错误的原因是您首先转换到使用新作用域实例化UsersIndexCtrl
的状态,然后在测试中创建另一个控制器实例(同样,使用新作用域)。 The two are independent of one another, and in the second instance, stateModels
is an unknown/unavailable dependency. 这两者是彼此独立的,在第二种情况下, stateModels
是未知/不可用的依赖。
So, while your ideas are valid testing concerns, in trying to assert all three together you are essentially performing an end-to-end test in a unit test environment. 因此,虽然您的想法是有效的测试问题,但在尝试将所有三个一起断言时,您实际上是在单元测试环境中执行端到端测试。 You should not want to - doing so will create a brittle dependency on: 你不应该这样做 - 这样做会产生一种脆弱的依赖:
Of these assertions, only the last is of any concern to the controller. 在这些断言中,只有最后一个与控制器有任何关系。 Unit tests for your controller don't care how/when it was instantiated or where the stateModels
dependency came from, they are only concerned with the controller's own behaviour. 控制器的单元测试不关心实例化的方式/时间或stateModels
依赖关系的来源,它们只关心控制器自身的行为。 So, let's split this behaviour up: 那么,让我们分开这个行为:
Unit testing the controller 单元测试控制器
Your first test should be reduced to the following: 您的第一次测试应该减少到以下几点:
it('binds the users to the scope', function(){
var stateModels = [{}, {}, {}];
$controller('UserIndexCtrl', {$scope: $scope, stateModels: stateModels});
assert.equal($scope.users, stateModels);
});
Note that as you add more tests, you will likely want to move your controller instantiation to a beforeEach
block. 请注意,在添加更多测试时,您可能希望将控制器实例化移动到beforeEach
块。
Testing the route 测试路线
The concern of testing a route is really that of application behaviour, for which you should defer to Protractor . 测试路径的关注点实际上是应用程序行为的问题,您应该遵循Protractor 。 However, if you particularly want to perform a unit test on a state, this is perhaps best served by testing the configuration of the state itself. 但是,如果您特别想对状态执行单元测试,则最好通过测试状态本身的配置来实现。 For example: 例如:
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.
});
That notwithstanding, I personally don't elect to unit test routing/route configuration, and instead acquire such coverage through e2e testing with Protractor. 尽管如此,我个人并不选择单元测试路由/路由配置,而是通过使用Protractor的e2e测试获得此类覆盖。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.