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
Testing $scope in AngularJs controller with dependency on $filter
提问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');

