在依赖于$ filter的AngularJs控制器中测试$ scope

Uli*_*ses 19 javascript jasmine angularjs

我已经完成了一些教程和基本的例子,但是我很难为我的控制器编写单元测试.我已经看到代码片段实例化控制器并让角度注入$rootScope对象,而对象又用于scope为控制器创建新对象.但我无法弄清楚为什么ctrl.$scope未定义:

 describe('EmployeeCtrl', function () {
    var scope, ctrl, $httpBackend;

    beforeEach(inject(function (_$httpBackend_, $rootScope, $controller, $filter) {
        $httpBackend = _$httpBackend_;       

        scope = $rootScope.$new();
        ctrl = $controller('EmployeeCtrl', { $scope: scope});
        expect(ctrl).not.toBeUndefined();
        expect(scope).not.toBeUndefined();   //<-- PASS!      
        expect(ctrl.$scope).not.toBeUndefined();  //<-- FAIL!       
    }));
});
Run Code Online (Sandbox Code Playgroud)

我最终使用scope变量而不是ctrl.$scope然后在我的第一次测试时我无法弄清楚如何在我的控制器内单元测试函数变量:

控制器:

 function EmployeeCtrl($scope, $http, $filter, Employee) {
  var searchMatch = function (haystack, needle) {
   return false;
  }
 }
Run Code Online (Sandbox Code Playgroud)

破损的单元测试:

it('should search ', function () {                
    expect(ctrl.searchMatch('numbers','one')).toBe(false);
});
Run Code Online (Sandbox Code Playgroud)

这就是我得到的

TypeError:Object#没有方法'searchMatch'

你如何测试这个功能?作为一种解决方法,我将我的方法移动到$ scope,所以我可以测试scope.searchMatch但是我想知道这是否是唯一的方法.

最后,在我的测试中看来$filter 也是未定义的,你如何注入它?我尝试了这个但是没有用:

ctrl = $controller('EmployeeCtrl', { $scope: scope, $filter: $filter });
Run Code Online (Sandbox Code Playgroud)

谢谢

更新: 上面提到的注入$ filter的方法工作得很好.

Rob*_*ert 40

我的理解是,在Angularjs中,当应用程序启动并且控制器修改范围时,您将范围对象传递给控制器​​.控制器不再被调用.

在Angularjs中,控制器真正做的是初始化范围:控制器只运行一次.如果您理解这一点,您会意识到向控制器询问范围如下:

currentScope = myController.scope;
Run Code Online (Sandbox Code Playgroud)

没有意义.

(顺便提一下,我在Angular中不喜欢的一个是他们选择的名称.如果'控制器'正在做的是初始化范围,那么它实际上不是一个控制器.在Angular中有很多这样的东西. API).

我认为测试'控制器'的'正确'方法是在Jasmine beforeEach子句中从头开始创建一个新的空白范围,并使用'controller' 初始化一个新的空白范围,如下所示::

var ctrl, myScope;

beforeEach(inject(function($controller, $rootScope) {
    myScope = $rootScope.$new();
    ctrl = $controller('myController', {
        $scope: myScope
    });
}));
Run Code Online (Sandbox Code Playgroud)

然后测试新创建的范围具有预期的属性:

it('In the scope, the initial value for a=2', function() {
            expect(myScope.a).toBe(2);
});
Run Code Online (Sandbox Code Playgroud)

换句话说,你不测试控制器; 您测试控制器已创建的范围.

所以,你做得对.