如何为AngularJS控制器注入大量依赖项

时间:2014-02-14 14:35:19

标签: javascript angularjs unit-testing jasmine

我正在尝试测试我的一个控制器。我的问题是创建的$LoginController对象始终是一个空对象,而我的方法都在范围对象上。然后,当我想测试 hasError函数,我收到一条消息:

TypeError:'undefined'不是对象(评估'$ 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 "";
    };

然后我将其注入元素类属性。那么我的代码哪一部分是错的,控制器还是测试?

1 个答案:

答案 0 :(得分: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_}
);