在AngularJS单元测试中设置$route.current.params的测试值
我在用O'Reilly AngularJS的书来学习AngularJS。然后在书中创建一个服务,该服务的任务是加载$resource,如下所示:在AngularJS单元测试中设置$route.current.params的测试值,angularjs,Angularjs,我在用O'Reilly AngularJS的书来学习AngularJS。然后在书中创建一个服务,该服务的任务是加载$resource,如下所示: services.factory('Recipe', ['$resource', function($resource) { return $resource('/recipes/:id', {id: '@id'}); }]); services.factory('RecipeLoader', ['Recipe', '$route', '$q',
services.factory('Recipe', ['$resource', function($resource) {
return $resource('/recipes/:id', {id: '@id'});
}]);
services.factory('RecipeLoader', ['Recipe', '$route', '$q', function(Recipe, $route, $q) {
return function() {
var delay = $q.defer();
Recipe.get({id: $route.current.params.recipeId}, function(recipe) {
delay.resolve(recipe);
}, function() {
delay.reject('Unable to fetch recipe ' + $route.current.params.recipeId);
});
return delay.promise;
};
});
然而,在书中,我忽略了测试这项服务,我正试图找出如何做到这一点。我已经创建了一个使用mock$httpBackend的测试,但是我遇到的问题是,当测试运行$route.current时,它是未定义的
我已尝试将$route注入测试并设置$route.current.params.id=1;但这似乎不起作用。有人对如何在$route.current.params中设置测试值有什么建议吗
非常感谢
解决方案
我找到了一个更好的解决方案,我让工厂采用id作为参数,如下所示:
services.factory('RecipeLoader', ['Recipe', '$route', '$q', function(Recipe, $route, $q) {
return function(recipeId) {
var delay = $q.defer();
Recipe.get({id: recipeId}, function(recipe) {
delay.resolve(recipe);
}, function() {
delay.reject('Unable to fetch recipe ' + $route.current.params.recipeId);
});
return delay.promise;
};
});
然后修改$routeProvider中的resolve参数以传入ID
.when('/recipe/view/:id', {
templateUrl: 'views/recipe/view.html',
controller: 'RecipeViewCtrl',
resolve: {
renewal: function (RecipeLoader, $route) {
return RecipeLoader($route.current.params.id);
}
}
})
无论如何,我觉得这是一个更好的设计,因为控制器更具体地说明了它需要什么输入。你是对的,你偶然发现的解决方案是创建和测试这项服务的更好方法。对于服务,它应该独立于magic,比如路由或状态,并且应该按照它需要的方式传递 书中的代码更多的是展示如何一起使用服务和解析,而不是编写服务的正确方式 对于服务,只要有可能,就更喜欢传入参数,而不是从magic state读取参数 也就是说,这是一个有趣的问题,当您需要测试依赖于某些服务的其他服务时,如何模拟这些服务 有两种方法可以覆盖测试中的服务:
初始化您自己的模块后,
,您可以按如下方式创建一个内联模块:
beforeEach(module(function($provide) {
$provide.factory('ServiceToOverride', function() {
// Return overriden service here
});
}));
链接如下:angular.module('myApp.mock')
,并在其中定义覆盖的服务。然后,在您的beforeach在测试中加载模块之后,还可以使用beforeach(module('myApp.mock'))加载此模块代码>
后者更适用于更密集和逻辑封装的模拟,而前者适用于快速、一次性、一次性的模拟。您必须模拟
$route
对象。只有在执行端到端测试或在完整浏览器中运行站点时,才会加载值。所以为了测试它,您需要为itThanks提供一个mock,我曾经怀疑过这一点,但我还不确定如何模拟$route(早期)。无论如何,我已经找到了一个更简洁的解决方案。请参阅原始帖子。感谢您的全面回复。非常有帮助!