我在指令中使用bindToController,将隔离范围直接附加到 Controller ,如下所示:
app.directive('xx', function () {
return {
bindToController: true,
controller: 'xxCtrl',
scope: {
label: '@',
},
};
});
然后在 Controller 中我有一个默认值,以防 HTML 中未指定标签:
app.controller('xxCtrl', function () {
var ctrl = this;
ctrl.label = ctrl.label || 'default value';
});
如何在 Jasmine 单元测试中实例化 xxCtrl 以便测试 ctrl.label?
describe('buttons.RemoveButtonCtrl', function () {
var ctrl;
beforeEach(inject(function ($controller) {
// What do I do here to set ctrl.label BEFORE the controller runs?
ctrl = $controller('xxCtrl');
}));
it('should have a label', function () {
expect(ctrl.label).toBe('foo');
});
});
检查this测试问题
最佳答案
在 Angular 1.3 中(1.4+ 版本见下文)
深入研究 AngularJS 源代码,我发现 $controller
服务有一个未记录的第三个参数,名为 later
(请参阅 $controller source )。
如果为 true,$controller()
返回一个带有属性 instance
的函数,您可以在该属性上设置属性。
当您准备好实例化 Controller 时,调用该函数,它将使用构造函数中可用的属性实例化 Controller 。
您的示例将像这样工作:
describe('buttons.RemoveButtonCtrl', function () {
var ctrlFn, ctrl, $scope;
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
ctrlFn = $controller('xxCtrl', {
$scope: scope,
}, true);
}));
it('should have a label', function () {
ctrlFn.instance.label = 'foo'; // set the value
// create controller instance
ctrl = ctrlFn();
// test
expect(ctrl.label).toBe('foo');
});
});
这是一个更新的 Plunker(必须升级 Angular 才能工作,现在是 1.3.0-rc.4):http://plnkr.co/edit/tnLIyzZHKqPO6Tekd804?p=preview
请注意,可能不建议使用它,引用 Angular 源代码:
Instantiate controller later: This machinery is used to create an instance of the object before calling the controller's constructor itself.
This allows properties to be added to the controller before the constructor is invoked. Primarily, this is used for isolate scope bindings in $compile.
This feature is not intended for use by applications, and is thus not documented publicly.
然而,由于缺乏使用 bindToController: true
测试 Controller 的机制,所以我还是使用了它。也许 Angular 的人应该考虑公开该标志。
它在底层使用了一个临时构造函数,我想我们也可以自己编写它。
您的解决方案的优点是构造函数不会被调用两次,如果属性没有像您的示例中那样具有默认值,这可能会导致问题。
Angular 1.4+(更新2015-12-06):
Angular 团队在 version 1.4.0 中添加了对此的直接支持。 (参见#9425)
您可以将一个对象传递给 $controller
函数:
describe('buttons.RemoveButtonCtrl', function () {
var ctrl, $scope;
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('xxCtrl', {
$scope: scope,
}, {
label: 'foo'
});
}));
it('should have a label', function () {
expect(ctrl.label).toBe('foo');
});
});
另请参阅 blog post .
关于angularjs - 单元测试中的bindToController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25837774/