测试 AngularUI Bootstrap 模态实例控制器 [英] Testing AngularUI Bootstrap modal instance controller

查看:24
本文介绍了测试 AngularUI Bootstrap 模态实例控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是这个问题的一个后续问题:在 AngularJS 单元测试中模拟 $modal

引用的 SO 是一个很好的问题,答案非常有用.然而,在此之后我留下的问题是:如何对模态实例控制器进行单元测试?在引用的 SO 中,测试了调用控制器,但模拟了模态实例控制器.可以说后者也应该被测试,但事实证明这是非常棘手的.原因如下:

我将从此处引用的 SO 中复制相同的示例:

.controller('ModalInstanceCtrl', function($scope, $modalInstance, items){$scope.items = 物品;$scope.selected = {项目:$scope.items[0]};$scope.ok = 函数 () {$modalInstance.close($scope.selected.item);};$scope.cancel = 函数 () {$modalInstance.dismiss('cancel');};});

所以我的第一个想法是直接在测试中实例化控制器,就像任何其他被测控制器一样:

beforeEach(inject(function($rootScope) {范围 = $rootScope.$new();ctrl = $controller('ModalInstanceCtrl', {$scope: scope});});

这不起作用,因为在这种情况下,angular 没有注入 $modalInstance 的提供程序,因为它是由 UI modal 提供的.

接下来,我转向B计划:使用$modal.open来实例化控制器.这将按预期运行:

beforeEach(inject(function($rootScope, $modal) {范围 = $rootScope.$new();modalInstance = $modal.open({模板:'<html></html>',控制器:'ModalInstanceCtrl',范围:范围});});

(注意,模板不能是空字符串,否则会神秘地失败.)

现在的问题是我对范围没有可见性,这是​​单元测试资源收集等的惯用方式.在我的实际代码中,控制器调用资源服务来填充选择列表;我试图测试这个设置了一个 expectGet 来满足我的控制器正在使用的服务,我想验证控制器是否将结果放在其范围内.但是模态正在为模态实例控制器创建一个作用域(使用我作为原型传入的作用域),我不知道如何获得该作用域的漏洞.modalInstance 对象没有进入控制器的窗口.

对正确"的测试方法有什么建议吗?

(注意:为模态实例控制器创建派生作用域的行为并不意外——这是记录在案的行为.无论如何,我关于如何测试它的问题仍然有效.)

解决方案

我通过直接实例化控制器来测试在模态对话框中使用的控制器(与您在上面最初想到的做法相同).

由于没有 $modalInstance 的模拟版本,我只是创建一个模拟对象并将其传递给控制器​​.

var modalInstance = { close: function() {},dismiss: function() {} };var 项目 = [];//任何...beforeEach(inject(function($rootScope) {范围 = $rootScope.$new();ctrl = $controller('ModalInstanceCtrl', {$范围:范围,$modalInstance: modalInstance,物品:物品});}));

现在控制器的依赖关系已经满足,您可以像测试任何其他控制器一样测试这个控制器.

例如,我可以执行 spyOn(modalInstance, 'close') 然后断言我的控制器正在适当的时间关闭对话框.

This is a somewhat of a follow-on question to this one: Mocking $modal in AngularJS unit tests

The referenced SO is an excellent question with very useful answer. The question I am left with after this however is this: how do I unit test the modal instance controller? In the referenced SO, the invoking controller is tested, but the modal instance controller is mocked. Arguably the latter should also be tested, but this has proven to be very tricky. Here's why:

I'll copy the same example from the referenced SO here:

.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');
  };
});

So my first thought was that I would just instantiate the controller directly in a test, just like any other controller under test:

beforeEach(inject(function($rootScope) {
  scope = $rootScope.$new();
  ctrl = $controller('ModalInstanceCtrl', {$scope: scope});
});

This does not work because in this context, angular does not have a provider to inject $modalInstance, since that is supplied by the UI modal.

Next, I turn to plan B: use $modal.open to instantiate the controller. This will run as expected:

beforeEach(inject(function($rootScope, $modal) {
  scope = $rootScope.$new();
  modalInstance = $modal.open({
    template: '<html></html>',
    controller: 'ModalInstanceCtrl',
    scope: scope
  });
});

(Note, template can't be an empty string or it will fail cryptically.)

The problem now is that I have no visibility into the scope, which is the customary way to unit test resource gathering, etc. In my real code, the controller calls a resource service to populate a list of choices; my attempt to test this sets an expectGet to satisfy the service my controller is using, and I want to validate that the controller is putting the result in its scope. But the modal is creating a new scope for the modal instance controller (using the scope I pass in as a prototype), and I can't figure out how I can get a hole of that scope. The modalInstance object does not have a window into the controller.

Any suggestions on the "right" way to test this?

(N.B.: the behavior of creating a derivative scope for the modal instance controller is not unexpected – it is documented behavior. My question of how to test it is still valid regardless.)

解决方案

I test the controllers used in modal dialogs by instantiating the controller directly (the same way you initially thought to do it above).

Since there there's no mocked version of $modalInstance, I simply create a mock object and pass that into the controller.

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
  });
}));

Now the dependencies for the controller are satisfied and you can test this controller like any other controller.

For example, I can do spyOn(modalInstance, 'close') and then assert that my controller is closing the dialog at the appropriate time.

这篇关于测试 AngularUI Bootstrap 模态实例控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆