在AngularJS单元测试中设置$route.current.params的测试值

在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',

我在用O'Reilly AngularJS的书来学习AngularJS。然后在书中创建一个服务,该服务的任务是加载$resource,如下所示:

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读取参数

也就是说,这是一个有趣的问题,当您需要测试依赖于某些服务的其他服务时,如何模拟这些服务

有两种方法可以覆盖测试中的服务:

  • 为了单个单元测试或描述块的目的,将其覆盖。在使用每个(模块('myModule'))之前的
    初始化您自己的模块后,
    ,您可以按如下方式创建一个内联模块:

    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(早期)。无论如何,我已经找到了一个更简洁的解决方案。请参阅原始帖子。感谢您的全面回复。非常有帮助!