如何使用 ngMock 注入 $controller
How to use ngMock to inject $controller
我正在尝试使用 Karma、Jasmine 和 ngMock 学习 Angular 的单元测试。 Angular 文档中至少有 2 个地方展示了如何为控制器编写单元测试,我只是有几个关于他们如何做事的问题。
来自Controller docs, section on testing controllers:
describe('myController function', function() {
describe('myController', function() {
var $scope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
$controller('MyController', {$scope: $scope});
}));
it("...");
});
});
问题 1: 这个 大部分 对我来说很有意义,但有些东西我不太明白。我知道 $controller
正在获取 "MyController" 的一个实例,但看起来返回的内容没有被保存或在任何地方使用,所以我唯一能想到的就是我们获取那个控制器为了获得正确的 $scope
对象?即便如此,它似乎也没有保存在任何地方的变量中,所以我仍然对它在幕后的工作方式感到困惑。我对 module()
的工作原理也有同样的困惑,因为我们似乎在声明我们正在使用哪个模块,但没有在其他任何地方保存或使用它。幕后是否有缓存 module/controller/scope 的东西,这样我们就不必手动保存它?
这是来自 Unit Testing docs 的另一个例子:
describe('PasswordController', function() {
beforeEach(module('app'));
var $controller;
beforeEach(inject(function(_$controller_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$controller = _$controller_;
}));
describe('$scope.grade', function() {
it('sets the strength to "strong" if the password length is >8 chars', function() {
var $scope = {};
var controller = $controller('PasswordController', { $scope: $scope });
$scope.password = 'longerthaneightchars';
$scope.grade();
expect($scope.strength).toEqual('strong');
});
});
});
问题 2: 在 beforeEach
函数中,它正在做下划线环绕的事情。这只是为了让您可以始终保持相同的服务名称而不必更改它吗?
问题 3: it()
块然后使用 $controller
做它的事情,这次保存返回给 var controller
但似乎仍然没有超过这一点。 那么为什么要将它保存到变量中呢?我唯一能想到的就是你保存它以防你需要在这个 it()
块中再次使用它,但他们只是没有在这个例子中?
我一直在寻找一个好的解释,但似乎找不到。抱歉,如果我遗漏了一个愚蠢的解释,但我时间紧迫,不能再花时间旋转我的轮子了。
1) 调用 module(‘myApp’) 将加载您的模块,本质上是 运行 所有模式函数(提供程序、指令、控制器)的声明,使它们可供您稍后使用。这就是 angular 在调用 $controller('myController') 时找到我的控制器的方式。
至于从 $controller 返回的控制器的引用,这取决于您的实现。如果您正在使用 $scope,一旦控制器被实例化,您就可以通过 $scope.
引用函数
在控制器中……
$scope.cancel = function () {
doStuff();
};
然后你的测试看起来像这样...
describe(’test Controller', function () {
var scope;
beforeEach(module(‘myApp'));
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
$controller(‘myController', {
$scope: scope
});
}));
describe(’testing stuff', function () {
it(’test cancel function', function () {
scope.cancel();
expect(...);
});
});
});
如果您使用 controllerAs 语法并将函数分配给控制器中的“this”,您可以在测试中使用对控制器的引用…
在控制器中……
this.cancel = function () {
doStuff();
};
然后你的测试看起来像这样...
describe(’test Controller', function () {
var scope,
controller;
beforeEach(module(‘myApp'));
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller(‘myController', {
$scope: scope
});
}));
describe(’testing stuff', function () {
it(’test cancel function', function () {
controller.cancel();
expect(...);
});
});
});
2) 是的,$controller 是为了避免名称冲突;
3) 我认为这是一个糟糕的例子,如果他们不使用它,他们就不需要保存它。我更喜欢在 beforeEach () 中完成我所有的测试设置。
@bobbyz:$controller 服务的第二个参数是注射剂的哈希值。当您为 $scope 添加引用时,根据控制器的定义创建控制器实例时,相同的引用对象将被修改。这样,$scope 就可以得到所有的方法或变量。
我正在尝试使用 Karma、Jasmine 和 ngMock 学习 Angular 的单元测试。 Angular 文档中至少有 2 个地方展示了如何为控制器编写单元测试,我只是有几个关于他们如何做事的问题。
来自Controller docs, section on testing controllers:
describe('myController function', function() {
describe('myController', function() {
var $scope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
$scope = $rootScope.$new();
$controller('MyController', {$scope: $scope});
}));
it("...");
});
});
问题 1: 这个 大部分 对我来说很有意义,但有些东西我不太明白。我知道 $controller
正在获取 "MyController" 的一个实例,但看起来返回的内容没有被保存或在任何地方使用,所以我唯一能想到的就是我们获取那个控制器为了获得正确的 $scope
对象?即便如此,它似乎也没有保存在任何地方的变量中,所以我仍然对它在幕后的工作方式感到困惑。我对 module()
的工作原理也有同样的困惑,因为我们似乎在声明我们正在使用哪个模块,但没有在其他任何地方保存或使用它。幕后是否有缓存 module/controller/scope 的东西,这样我们就不必手动保存它?
这是来自 Unit Testing docs 的另一个例子:
describe('PasswordController', function() {
beforeEach(module('app'));
var $controller;
beforeEach(inject(function(_$controller_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$controller = _$controller_;
}));
describe('$scope.grade', function() {
it('sets the strength to "strong" if the password length is >8 chars', function() {
var $scope = {};
var controller = $controller('PasswordController', { $scope: $scope });
$scope.password = 'longerthaneightchars';
$scope.grade();
expect($scope.strength).toEqual('strong');
});
});
});
问题 2: 在 beforeEach
函数中,它正在做下划线环绕的事情。这只是为了让您可以始终保持相同的服务名称而不必更改它吗?
问题 3: it()
块然后使用 $controller
做它的事情,这次保存返回给 var controller
但似乎仍然没有超过这一点。 那么为什么要将它保存到变量中呢?我唯一能想到的就是你保存它以防你需要在这个 it()
块中再次使用它,但他们只是没有在这个例子中?
我一直在寻找一个好的解释,但似乎找不到。抱歉,如果我遗漏了一个愚蠢的解释,但我时间紧迫,不能再花时间旋转我的轮子了。
1) 调用 module(‘myApp’) 将加载您的模块,本质上是 运行 所有模式函数(提供程序、指令、控制器)的声明,使它们可供您稍后使用。这就是 angular 在调用 $controller('myController') 时找到我的控制器的方式。
至于从 $controller 返回的控制器的引用,这取决于您的实现。如果您正在使用 $scope,一旦控制器被实例化,您就可以通过 $scope.
引用函数在控制器中……
$scope.cancel = function () {
doStuff();
};
然后你的测试看起来像这样...
describe(’test Controller', function () {
var scope;
beforeEach(module(‘myApp'));
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
$controller(‘myController', {
$scope: scope
});
}));
describe(’testing stuff', function () {
it(’test cancel function', function () {
scope.cancel();
expect(...);
});
});
});
如果您使用 controllerAs 语法并将函数分配给控制器中的“this”,您可以在测试中使用对控制器的引用…
在控制器中……
this.cancel = function () {
doStuff();
};
然后你的测试看起来像这样...
describe(’test Controller', function () {
var scope,
controller;
beforeEach(module(‘myApp'));
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller(‘myController', {
$scope: scope
});
}));
describe(’testing stuff', function () {
it(’test cancel function', function () {
controller.cancel();
expect(...);
});
});
});
2) 是的,$controller 是为了避免名称冲突;
3) 我认为这是一个糟糕的例子,如果他们不使用它,他们就不需要保存它。我更喜欢在 beforeEach () 中完成我所有的测试设置。
@bobbyz:$controller 服务的第二个参数是注射剂的哈希值。当您为 $scope 添加引用时,根据控制器的定义创建控制器实例时,相同的引用对象将被修改。这样,$scope 就可以得到所有的方法或变量。