在测试中模拟$ routeParams以动态更改其属性 [英] Mocking $routeParams in a test in order to change its attributes dynamically
问题描述
我的控制器测试取决于Angular $ routeParams服务:
I have a controller test that depends on the Angular $routeParams service:
var $routeParams, MainCtrl, scope;
beforeEach(inject(function ($controller, $rootScope, $injector, $templateCache) {
scope = $rootScope.$new();
$routeParams = $injector.get('$routeParamsMock');
MainCtrl = $controller('MainCtrl', {
$scope: scope,
$routeParams: $routeParams,
});
}));
it('should load a pg from $routeParams', function(){
scope.userData = {};
$routeParams._setPg('PG_FIRST');
scope.$digest();
timeout.flush();
expect(scope.userData.pg).toBe(0);
$routeParams._setPg('PG_SECOND');
scope.$digest();
timeout.flush();
expect(scope.userData.pg).toBe(1);
});
$ routeParamsMock:
!(function(window, angular){
'use strict';
angular.module('vitaApp')
.service('$routeParamsMock', function() {
var _pg = null;
return{
pg: _pg,
_setPg: function(pg){
_pg = pg;
}
}
});
})(window, window.angular);
调试测试时,我惊讶地发现$ routeParamsMock.pg每次都返回null时间,即使我用不同的值调用_setPg。
When debugging the test, I was surprised to find out that $routeParamsMock.pg was returning null every single time, even though I called _setPg with a different value.
是否因为null被认为是一个原语(具有一种对象......),因此通过值?,或者可能是因为Angular正在复制传递给$ controller服务的对象?。
Is it because null is considered a primitive (with a type of object...), and thus passed by value?, or perhaps because Angular is copying the object that is passed to the $controller service?.
我正在寻找的解决方案最好是不需要的解决方案根据不同的测试场景实现不同的控制器。
例如:
The solution I am looking for is preferably one that won't require to instanciate different controllers per different test scenerios. eg:
MainCtrl = $controller('MainCtrl', {
$scope: scope,
$routeParams: {'pg': 'PG_FIRST'},
});
MainCtrl = $controller('MainCtrl', {
$scope: scope,
$routeParams: {'pg': 'PG_SECOND'},
});
推荐答案
事情是,你不想要什么你可能是最好的解决方案。当你想要模拟的东西有点复杂时, mock
是有意义的。与方法,许多状态等的复杂依赖关系对于像 $ routeParams
这样的简单对象,它让世界感觉只是将虚拟对象传递给它。是的,它需要在每个测试中实例化不同的控制器,但那又是什么?
The thing is, what you don't want to do, is probably the best solution you have. A mock
makes sense when what you want to mock is kinda complex. Complex dependency with methods, lot of states, etc. For a simple object like $routeParams
it makes all the sense of the world to just pass a dummy object to it. Yes it would require to instantiate different controllers per test, but so what?
以有意义的方式构建测试,使其易读且易于理解。
Structure your tests in a way that makes sense, makes it readable and easy to follow.
我建议你这样:
describe('Controller: Foo', function() {
var $controller, $scope;
beforeEach(function() {
module('app');
inject(function($rootScope, _$controller_) {
$scope = $rootScope.$new();routeParams = {};
$controller = _$controller_;
});
});
describe('With PG_FIRST', function() {
beforeEach(function() {
$controller('Foo', { $scope: $scope, $routeParams: {'PG': 'PG_FIRST'}});
});
it('Should ....', function() {
expect($scope.something).toBe('PG_FIRST');
});
});
describe('With PG_SECOND', function() {
beforeEach(function() {
$controller('Foo', { $scope: $scope, $routeParams: {'PG': 'PG_SECOND'}});
});
it('Should ....', function() {
expect($scope.something).toBe('PG_SECOND');
});
});
});
有了一个好的测试组织,我可以说我喜欢这个测试很容易理解。
With a good test organization, I can say that I like this test easy to follow.
http://plnkr.co/edit/5Q3ykv9ZB7PuGFMfWVY5 ?p =预览
这篇关于在测试中模拟$ routeParams以动态更改其属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!