繁体   English   中英

测试AngularUI Bootstrap模式实例控制器

[英]Testing AngularUI Bootstrap modal instance controller

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

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

我将在这里复制引用的SO中的相同示例:

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

(注意,模板不能是空字符串,否则会以密码方式失败。)

现在的问题是我无法看到范围,这是单元测试资源收集的习惯方式等。在我的实际代码中,控制器调用资源服务来填充选择列表; 我尝试测试这个设置expectGet以满足我的控制器正在使用的服务,我想验证控制器是否将结果放在其范围内。 但模式是为模态实例控制器创建一个新的范围(使用我作为原型传入的范围),我无法弄清楚如何获得该范围的漏洞。 modalInstance对象没有进入控制器的窗口。

有关“正确”测试方法的任何建议吗?

(注意:为模态实例控制器创建衍生作用域的行为并不是意料之外的 - 它是记录在案的行为。无论如何,我对如何测试它的问题仍然有效。)

我通过直接实例化控制器来测试模态对话框中使用的控制器(就像你最初想的那样)。

由于没有模拟版本的$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
  });
}));

现在,控制器的依赖性得到满足,您可以像任何其他控制器一样测试此控制器。

例如,我可以执行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()

it('should let the user dismiss the modal', function () {
  expect($scope.cancel).toBeDefined();
  $scope.cancel();
  expect($uibModalInstance.dismiss).toHaveBeenCalled();
});

it('should let the user confirm the modal', function () {
  expect($scope.confirm).toBeDefined();
  $scope.confirm();
  expect($uibModalInstance.close).toHaveBeenCalled();
});

同样的问题是$ uidModalInstance,你可以用类似的方式解决它:

var uidModalInstance = { close: function() {}, dismiss: function() {} };

$ctrl = $controller('ModalInstanceCtrl', {
   $scope: $scope,
   $uibModalInstance: uidModalInstance
});

或者如所说@yvesmancera你可以使用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(),dismiss()将作为测试的一部分被调用

    it('确认模态 - 验证确认操作,关于ok()调用调用modalInstance close()function',function(){action ='Ok'; scopeStub.item = testItem; createController(); scopeStub.ok();} );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM