问题描述
我已经阅读了一些教程和基本示例,但是我很难为我的控制器编写单元测试.我已经看到代码片段实例化控制器并让 angular 注入 $rootScope
对象,该对象又用于为控制器创建一个新的 scope
对象.但我不明白为什么 ctrl.$scope
?未定义:
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 $rootScope
object which in turn is used to create a new scope
object for the controller. But I can't figure out why ctrl.$scope
? is undefined:
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!
}));
});
我最终使用了 scope
变量而不是 ctrl.$scope
但是在我的第一次测试中我无法弄清楚如何对 进行单元测试控制器内部的函数变量:
I ended up using the scope
variable instead of ctrl.$scope
but then on my first test I couldn't figure out how to unit test a function variable inside my controller:
控制器:
function EmployeeCtrl($scope, $http, $filter, Employee) {
var searchMatch = function (haystack, needle) {
return false;
}
}
损坏的单元测试:
it('should search ', function () {
expect(ctrl.searchMatch('numbers','one')).toBe(false);
});
这是我得到的
TypeError: Object # 没有方法 'searchMatch'
您如何测试该功能?作为一种解决方法,我将我的方法移至 $scope 以便我可以测试 scope.searchMatch
但我想知道这是不是唯一的方法.
How do you test that function? As a workaround I moved my method to $scope so I could test for scope.searchMatch
but I was wondering if this is the only way.
最后,在我的测试中出现$filter
未定义,你如何注入它?我试过了,但没有用:
Finally, on my tests is appears $filter
is undefined too, how do you inject it? I tried this but didn't work:
ctrl = $controller('EmployeeCtrl', { $scope: scope, $filter: $filter });
谢谢
更新:上面提到的注入 $filter 的方法工作得很好.
Update:The method mentioned above to inject $filter works just fine.
推荐答案
我的理解是,在 Angularjs 中,您在应用程序启动时将范围对象传递给控制器并且控制器修改范围.控制器不再被调用.
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:
currentScope = myController.scope;
没有意义.
(顺便说一句,我不喜欢 Angular 中的一件事是他们选择的名称.如果控制器"正在做的是初始化范围,那么它并不是真正的控制器.有很多这样的在 Angular API 中).
(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).
我认为测试控制器"的正确"方法是在 Jasmine beforeEach 子句中从头开始创建一个新的空白范围,并使用控制器"进行初始化 一个像这样的新空白范围::
I think that the 'proper' way for testing a 'controller' is creating a new blank scope from scratch in a Jasmine beforeEach clause and using the 'controller' for initializing a new blank scope like this::
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.
所以,你做对了.
这篇关于在依赖于 $filter 的 AngularJs 控制器中测试 $scope的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!