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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14202767/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 16:00:58  来源:igfitidea点击:

Testing $scope in AngularJs controller with dependency on $filter

javascriptangularjsjasmine

提问by Ulises

I've gone through a few tutorials and basic examples but I'm having a hard time writing unit tests for my controller. I've seen code snippets instantiating controllers and letting angular inject the $rootScopeobject which in turn is used to create a new scopeobject for the controller. But I can't figure out why ctrl.$scope? is undefined:

我已经阅读了一些教程和基本示例,但是我很难为我的控制器编写单元测试。我已经看到代码片段实例化控制器并让 angular 注入$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!       
    }));
});

I ended up using the scopevariable instead of ctrl.$scopebut then on my first test I couldn't figure out how to unit test a function variableinside my controller:

我最终使用了scope变量而不是,ctrl.$scope但在我的第一次测试中,我无法弄清楚如何对控制器内的函数变量进行单元测试:

Controller:

控制器:

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

Broken unit test:

损坏的单元测试:

it('should search ', function () {                
    expect(ctrl.searchMatch('numbers','one')).toBe(false);
});

This is what I get

这就是我得到的

TypeError: Object # has no method 'searchMatch'

类型错误:对象 # 没有方法“searchMatch”

How do you test that function? As a workaround I moved my method to $scope so I could test for scope.searchMatchbut I was wondering if this is the only way.

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

Finally, on my tests is appears $filteris undefined too, how do you inject it? I tried this but didn't work:

最后,在我的测试中似乎$filter也未定义,你如何注入它?我试过这个但没有用:

ctrl = $controller('EmployeeCtrl', { $scope: scope, $filter: $filter });

Thanks

谢谢

Update:The method mentioned above to inject $filter works just fine.

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

回答by Robert

My understanding is that, in Angularjs, you pass a scope object to the controller when the application is starting and the controller modify the scope. The controller is not called anymore.

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

What a controller is really doing, in Angularjs, is initializing the scope: the controller only runs one time. If you understand this, you realize that asking to the controller for the scope like this:

在 Angularjs 中,控制器真正做的是初始化作用域:控制器只运行一次。如果你理解了这一点,你就会意识到向控制器请求范围是这样的:

currentScope = myController.scope;

doesn't makes sense.

没有意义。

(Incidentally, one of the things I don't like in Angular is the names that they have choosen. If what a 'controller' is doing is initializing the scope then it's not really a controller. There are a lot of this in the Angular API).

(顺便说一句,我在 Angular 中不喜欢的一件事是他们选择的名称。如果“控制器”所​​做的是初始化范围,那么它并不是真正的控制器。Angular 中有很多这样的东西API)。

I think that the 'proper' way for testing a 'controller' is creating a new blank scope from scratch in a Jasmine beforeEachclause and using the 'controller' for initializinga new blank scope like this::

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

var ctrl, myScope;

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

And then testing the new created scope has the expected properties:

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

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

In other words, you don't test the controller; you test the scope that the controller has created.

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

So, you're doing it right.

所以,你做对了。

回答by Guy

Here is another pattern that might be simpler to follow:

这是另一种可能更容易遵循的模式:

var $scope;
beforeEach(module(function ($provide) {
  $scope = {
    // set anything you want here or nothing
  };
  $provide.value('$scope', $scope);
}));

var ctrl;
beforeEach(inject(function ($controller) {
  ctrl = $controller('MyController');
}));

it('should test something...', function () {
  // $scope will have any properties set by
  // the controller so you can now do asserts
  // on them.
});

You can use this same pattern to set values for $location and $window as well as others.

您可以使用相同的模式为 $location 和 $window 以及其他设置值。

回答by asgoth

There are only two possibilities:

只有两种可能:

Add searchMatchto the scope (as you mentioned) or

添加searchMatch到范围(如您所述)或

Return the searchMatchfunction:

返回searchMatch函数:

function EmployeeCtrl($scope, $http, $filter, Employee) {
  return {
    searchMatch: function (haystack, needle) {
      return false;
    }
  };
 }

If it really must stay private, then you'll have to test the features which use it.

如果它真的必须保持私密,那么您将不得不测试使用它的功能。

To get the $filter, you can try the following:

要获得$filter,您可以尝试以下操作:

var $filter = angular.injector(['ng']).get('$filter');