Javascript 测试AngularUI引导模式实例控制器
这是这个问题的后续问题: 参考SO是一个很好的问题,答案非常有用。然而,在这之后我剩下的问题是:如何对模态实例控制器进行单元测试?在引用的SO中,测试调用控制器,但模拟模态实例控制器。可以说,后者也应该进行测试,但事实证明这是非常棘手的。原因如下: 我将从引用的示例中复制相同的示例,因此:Javascript 测试AngularUI引导模式实例控制器,javascript,angularjs,unit-testing,angular-ui,Javascript,Angularjs,Unit Testing,Angular Ui,这是这个问题的后续问题: 参考SO是一个很好的问题,答案非常有用。然而,在这之后我剩下的问题是:如何对模态实例控制器进行单元测试?在引用的SO中,测试调用控制器,但模拟模态实例控制器。可以说,后者也应该进行测试,但事实证明这是非常棘手的。原因如下: 我将从引用的示例中复制相同的示例,因此: .controller('ModalInstanceCtrl', function($scope, $modalInstance, items){ $scope.items = items; $sco
.controller('ModalInstanceCtrl', function($scope, $modalInstance, items){
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
因此,我的第一个想法是,我将在测试中直接实例化控制器,就像任何其他正在测试的控制器一样:
beforeEach(inject(function($rootScope) {
scope = $rootScope.$new();
ctrl = $controller('ModalInstanceCtrl', {$scope: scope});
});
这不起作用,因为在此上下文中,angular没有用于注入$modalInstance的提供程序,因为它是由UI模式提供的
接下来,我转向计划B:使用$modal.open实例化控制器。这将按预期运行:
beforeEach(inject(function($rootScope, $modal) {
scope = $rootScope.$new();
modalInstance = $modal.open({
template: '<html></html>',
controller: 'ModalInstanceCtrl',
scope: scope
});
});
beforeach(注入(函数($rootScope,$modal){
scope=$rootScope.$new();
modalInstance=$modal.open({
模板:“”,
控制器:“ModalInstanceCtrl”,
范围:范围
});
});
(请注意,模板不能为空字符串,否则将以加密方式失败。)
现在的问题是,我对范围没有可见性,这是单元测试资源收集等的惯常方式。在我的实际代码中,控制器调用资源服务来填充一个选项列表;我尝试测试它时设置了一个expectGet以满足我的控制器正在使用的服务,我想验证控制器正在将结果放入其作用域。但是模态正在为模态实例控制器创建一个新的作用域(使用我传入的作用域作为原型),我不知道如何获得该作用域的一个洞。modalInstance对象没有进入控制器的窗口
var modalInstance = { close: function() {}, dismiss: function() {} };
var items = []; // whatever...
beforeEach(inject(function($rootScope) {
scope = $rootScope.$new();
ctrl = $controller('ModalInstanceCtrl', {
$scope: scope,
$modalInstance: modalInstance,
items: items
});
}));
关于测试这个的“正确”方法有什么建议吗
(注意:为模态实例控制器创建派生作用域的行为并非意外–它是有文档记录的行为。我关于如何测试它的问题仍然有效。)我通过直接实例化控制器来测试模态对话框中使用的控制器(与您最初认为的方法相同) 由于没有模拟版本的
$modalInstance
,我只需创建一个模拟对象并将其传递给控制器
var modalInstance = { close: function() {}, dismiss: function() {} };
var items = []; // whatever...
beforeEach(inject(function($rootScope) {
scope = $rootScope.$new();
ctrl = $controller('ModalInstanceCtrl', {
$scope: scope,
$modalInstance: modalInstance,
items: items
});
}));
现在控制器的依赖关系已经满足,您可以像测试任何其他控制器一样测试该控制器
var modalInstance = { close: function() {}, dismiss: function() {} };
var items = []; // whatever...
beforeEach(inject(function($rootScope) {
scope = $rootScope.$new();
ctrl = $controller('ModalInstanceCtrl', {
$scope: scope,
$modalInstance: modalInstance,
items: items
});
}));
例如,我可以执行
spyOn(modalInstance,'close')
,然后断言我的控制器正在适当的时间关闭对话框。或者,如果您使用的是jasmine,您可以使用createSpy
方法模拟$uibModalInstance
:
beforeEach(inject(function ($controller, $rootScope) {
$scope = $rootScope.$new();
$uibModalInstance = jasmine.createSpyObj('$uibModalInstance', ['close', 'dismiss']);
ModalCtrl = $controller('ModalCtrl', {
$scope: $scope,
$uibModalInstance: $uibModalInstance,
});
}));
在不必对每个方法调用spyOn
的情况下对其进行测试,假设您有两个作用域方法,cancel()
和confirm()
:
$uidModalInstance也存在同样的问题,您可以用类似的方法解决它:
var uidModalInstance = { close: function() {}, dismiss: function() {} };
$ctrl = $controller('ModalInstanceCtrl', {
$scope: $scope,
$uibModalInstance: uidModalInstance
});
或者,正如@yvemancera所说,您可以使用jasmine.createSpy方法,例如:
var uidModalInstance = jasmine.createSpyObj('$uibModalInstance', ['close', 'dismiss']);
$ctrl = $controller('ModalInstanceCtrl', {
$scope: $scope,
$uibModalInstance: uidModalInstance
});
遵循以下给定步骤:
- 定义ModalInstance的存根,如下所示
uibModalInstanceStub = { close: sinon.stub(), dismiss: sinon.stub() };
- 在创建控制器时传递模态实例存根
function createController() { return $controller( ppcConfirmGapModalComponentFullName, { $scope: scopeStub, $uibModalInstance: uibModalInstanceStub }); } });
- Stub方法close(),disclose()将作为测试的一部分被调用 它('confirm modal-verify confirm action,on ok()调用调用modalInstance close()函数',函数(){ 动作=‘Ok’; scopeStub.item=测试项; createController(); scopeStub.ok(); }))
参数'ModalInstanceCtrl'不是一个函数,没有定义。
…即使Sunil D的答案肯定有效,我觉得这绝对应该是大多数sinc实现的公认答案e你很可能会想监视他们。如果你不想这样,那么Sunil D的工作非常出色。还有一点。我同意,我发现自己用这种方式为模拟对象创建间谍,而不是我上面所做的。@perry谢谢你!但是这个问题没有被标记为jasmine,甚至没有被提及,所以Sunil的答案适用于任何测试框架,而我的答案适用于只有当你用的是茉莉花的时候。@yvesmancera这是真的。我想我错过了。所以当我看到角度测试的时候,我的大脑就进入了茉莉花:D@perryFWIW:我在选定的答案中使用了Sunil的方法,spyOn可以很好地使用它。