2014-02-14 180 views
1

我想测试我的控制器之一。我的问题是创建的$LoginController对象始终是一个空对象,而我的方法都在该作用域对象上。然后,当我想测试 hasError功能,我得到一个消息:如何注入AngularJS控制器与大量的依赖项

类型错误:“未定义”不是一个对象(计算“$ route.current.params”)

这里是我的测试:

describe('login', function() { 
     var $LoginController = null, $scope, $route, $location, $httpBackend; 
     beforeEach(module('common.base64')); 
     beforeEach(module('myapp.user')); 

     beforeEach(inject(function ($injector, $controller, $rootScope, 
            _$location_, _$timeout_, _$route_, _Base64_) 
     { 
      $httpBackend = $injector.get('$httpBackend'); 
      $scope = $rootScope.$new(); 
      $route = _$route_; 
      $location = _$location_; 
      $LoginController = $controller('LoginController', { 
       $scope : $scope, $http: $httpBackend, $location: _$location_, 
       $timeout: _$timeout_, $route: _$route_, Base64: _Base64_} 
      ); 
      console.log($LoginController); // <-- Log: {} 
      console.log($scope);   // <-- Log: { <lots of stuff> } 
     })); 

     describe('LoginController', function() { 
      it('should have been injected', inject(function() { 
        expect($LoginController).toBeTruthy(); 
       } 
      )); 
     }); 

     describe('hasError', function() { 
       it('should return error', inject(function() { 
         $location.url('/login?loginError=true'); 

         expect($scope.hasError).toBeTruthy();   
            // ^-- hasError is defined! 
         expect($LoginController.hasError).toBeTruthy(); 
         //      ^-- hasError is undefined! 
        } 
       )); 
      } 
     ); 
    } 
); 

在我的LoginController的hasError函数的定义是这样的:

$scope.hasError = function() { 
     if($route.current.params) { 
      if ($route.current.params['loginError']) { 
       return "error"; 
      } else { 
       return ""; 
      } 
     } 
     return ""; 
    }; 

然后我将其注入到一个元素类属性中。那么我的代码片段错了,控制器还是测试?

+0

测试。为什么控制器上会出现hasError方法? hasError是作用域的一种方法,正如控制器的代码所示。请注意,您不需要注入所有未在测试中使用的服务,例如Base64,$ route和$ timeout。 –

+0

将函数赋值给'this'然后设置'$ scope.LoginController = this'是否更好? – lanoxx

+1

有些人这样做。我个人认为没有优势。 'this'处理在JavaScript中是一场噩梦,并且该视图必须使用LoginController.foo()而不是简单地使用foo()。 –

回答

4

您的测试是。

由于您在此处的测试中未使用任何路由,因此不会有当前的路由可供使用。

,如果你需要

_$route_.current = { 
    params: { 
    loginError: 12345 
    } 
}; 

$location和其他几件事情都得到与嘲笑换出,如果您使用的是ng-mock模块......它看起来你是可以明确此设置。因此更改$location不会触发路线更改。

更好的解决方案是将控制器更改为使用$routeParams依赖项,而不是访问当前路由本身。通过这种方式,您可以在创建测试期间将其传入。

if($routeParams && $routeParams.loginError) { 
    return "error"; 
} 

return ""; 

然后在你的测试,你可以简单地通过在$routeParams

$LoginController = $controller('LoginController', { 
    $scope : $scope, $http: $httpBackend, $location: _$location_, 
    $timeout: _$timeout_, 

    // Mock out $routeParams here: 
    $routeParams: {loginError: 'blah' }, 

    Base64: _Base64_} 
);