【问题标题】:AngularJS error: Unexpected request (No more requests expected)AngularJS 错误:意外请求(预期没有更多请求)
【发布时间】:2014-12-14 15:53:10
【问题描述】:

在我的 AngularJS 应用程序中,我无法弄清楚如何对 then promise 的执行更改 location.url 进行单元测试。我有一个函数 login,它调用服务 AuthenticationService。它返回promise,然后promise的执行会改变location.url。

这是控制器AuthCtrl

angular
  .module('bloc1App')
  .controller('AuthCtrl', ['$scope', '$http','$location', 'AuthenticationService',
  function($scope, $http, $location, AuthenticationService) { 

   this.AuthenticationService = AuthenticationService;
   var self = this;

  $scope.login = function(username, password){
    self.AuthenticationService
      .login(username, password)
      .then(function(){
        $location.url('/tasks');
      });
  };
 }
]);

这是我在单元测试中的尝试:

    describe('Controller: AuthCtrl', function () {

      var scope,
          location,
          route,
          q,
          rootScope,
          AuthCtrl;

      beforeEach(module('bloc1App'));

      beforeEach(inject(function($controller, $rootScope, $location, $route, $q) {
        scope = $rootScope.$new();
        q = $q;
        rootScope = $rootScope;
        location = $location;
        route = $route;

      AuthCtrl = $controller('AuthCtrl', {
         $scope: scope,
         $route: route,
         $location: location
      });

    }));

    it('login should redirect user to tasks view', function(){
      var deferred = q.defer();
      spyOn(AuthCtrl.AuthenticationService, 'login').andReturn(deferred.promise);
      spyOn(location, 'url');
      scope.login('foo', 'foo');
      deferred.resolve();
      scope.$apply();
      expect(location.url).toHaveBeenCalledWith('/tasks');
    });
   });

当我运行这个测试时,我得到了这个错误。如果我使用 rootScope.$apply() 代替,我会得到同样的错误:

Error: Unexpected request: GET views/AuthView.html
No more request expected

当我取出 scope.$apply() 时,我得到这个错误:

Expected spy url to have been called with [ '/tasks' ] but it was never called.

关于如何解决这个问题的任何想法?这是我第一次对 Promise 进行单元测试,我可能在概念上误解了如何执行此操作。

提前感谢您的帮助。

【问题讨论】:

    标签: angularjs unit-testing jasmine


    【解决方案1】:

    当您使用 AngularJS 进行单元测试时,您实际上是在使用来自 ngMock 模块的模拟服务,而不是真正的服务。在这种情况下,您的错误可能来自 $httpBackend 模拟,如果您希望测试单元使用 $http 发送真实请求,则必须首先“启动”它。 (我在任何地方都没有看到您使用 $http 的代码,所以我猜您这里没有显示的部分。)

    基本上,您需要使用$httpBackend.when 告诉$httpBackend 模拟您期待一个特定请求(或者您可以使用$httpBackend.expect,如果您希望模拟检查该请求是否真的被调用)和应该返回什么响应。

    因此,您的错误与承诺无关,而与连接到服务器的测试单元有关。

    【讨论】:

    • 感谢您的及时回复!服务 AuthenticationService 发出 http 请求。因为我正在测试控制器,所以我认为这无关紧要。但是,我采纳了您的建议并使用 expect 添加了 httpBackend 模拟,现在单元测试可以工作了!
    【解决方案2】:

    在提出问题近两年后回答这个问题可能没有实际意义,但公认的答案并不完全正确。问题是您没有正确模拟AuthenticationService。您应该完全模拟服务的功能,只测试 服务已从控制器调用,并保存 $httpBackend 内容以测试服务本身。你想要做的是将一个假的AuthenticationService(以及 Angular 服务的模拟实例,如$q$location$route,如果我们遵循最佳实践)注入beforeEach,然后在$controller 定义中声明它。您还可以在 beforeEach 块中包含您的间谍。

    describe('AuthCtrl', function(){
    
      var $q;
      var $location;
      var $controller;
      var AuthenticationService;
      var $route;
      var deferred;
    
      beforeEach(inject(function( _$controller_, $rootScope, _AuthenticationService_, _$q_, _$location_, _$route_){
    
        scope = $rootScope.$new();
        AuthenticationService = _AuthenticationService_;
        $location = _$location_;
        $route = _$route_;
        $controller = _$controller_;
        $q = _$q_;
        deferred = $q.defer();
    
        spyOn(AuthenticationService, 'login').andReturnValue(deferred.promise);
        spyOn($location, 'url');
    
        AuthCtrl = $controller('AuthCtrl', {
          scope: scope,
          AuthenticationService: AuthenticationService,
          $route: $route,
          $location: $location
        };
    
      }));
    
      it('should redirect the user on login', function(){
          deferred.resolve();
          scope.$apply();
          expect($location.url).toHaveBeenCalledWith('/tasks');
      }); 
    });
    

    请注意,如果您以这种方式定义变量,则将控制器定义放在 beforeEach 块中的最后一项非常重要,否则模拟将无法正确实例化并且将实际调用服务方法,无论间谍。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-17
      • 2017-06-29
      相关资源
      最近更新 更多