25

编辑modalInstance控制器:在这篇文章单元测试与噶/茉莉花

我使用从AngularUI自举模式窗口以同样的方式结束快速&肮脏的解决方案,它是在解释网站,除了我分裂的文件。 因此我有:

CallingController.js:

$scope.delete = function() { 
    if ($scope.selected.length > 0) { 
     // [...] 
     // preparing data 
     // [...] 
     var modalInstance = $modal.open({ 
      templateUrl: 'views/modalView.html', 
      controller: 'modalCtrl', 
      resolve: { 
       itemArray: function() { 
        return $scope.selected; 
       } 
      } 
     }); 
     modalInstance.result.then(function (confirm) { 
      if (confirm === true) { 
       // [...] 
       // treat 
       // [...] 
      } 
     }); 
    } 
}; 

modalController.js:

myAppControllers.controller('modalCtrl', 
    function ($scope, $modalInstance, itemArray) { 

     $scope.accept = function() { 
      $modalInstance.close(true); 
     }; 

     $scope.reject = function() { 
      $modalInstance.close(false); 
     }; 

     $scope.itemArray = itemArray; 

    }); 

,当我测试此代码与噶(与UI的自举-tpls.min.js文件在karma配置文件中加载),我得到以下错误: 错误:[$注射器:unpr] [?http://errors.angularjs.org/1.2.15-build.2389+sha.c5f2f58/ $喷油器/ unpr P0 =%24modalInstanceProvider%20%3 C-%20%24modalInstance] 1在错误(原生),这意味着茉莉花不设法找到供应商为$ modalInstance。

我,甚至不测试的东西这个控制器上,目前还没有,但这里是我的茉莉花测试文件:

testModalController.js:

describe('Controller: modalCtrl', function() { 

    beforeEach(module('myApp')); 

    var Ctrl; 
    var scope; 

    // Initialize the controller and a mock scope 
    beforeEach(inject(
     function ($controller, $rootScope) { 
      scope = $rootScope.$new(); 

      Ctrl = $controller('modalCtrl', { $scope: scope }); 
     }) 
    ); 

    describe('Initial state', function() { 
     it('should instantiate the controller properly', function() { 
      expect(Ctrl).not.toBeUndefined(); 
     }); 

     it('should initialize its values properly', function() { 

     }); 
    }); 

}); 

你有关于这个问题的任何线索?这不是我使用(和测试)的第一个“外部”模块,除了这一次不起作用,我不知道为什么。

==========================================

编辑:快速&大概肮脏的解决方案:

好了,所以基于在茉莉花的控制器实例范围嘲讽的方法,我想通了,我怎么能“解决”我的问题,但它可能是很肮脏的,所以如果你找到更好的方式去做我想要的东西,请随时发表评论。

testModalController.js:

describe('Controller: modalCtrl', function() { 

    beforeEach(module('myApp')); 

    var Ctrl; 
    var scope; 
    var modalInstance; 

    // Initialize the controller and a mock scope 
    beforeEach(inject(
     function ($controller, $rootScope, _$modal_) { 
      scope = $rootScope.$new(); 
      modalInstance = _$modal_.open({ 
       templateUrl: 'views/modalView.html' 
      }); 

      Ctrl = $controller('modalCtrl', { 
       $scope: scope, 
       $modalInstance: modalInstance, 
       itemArray: function() { return ['a', 'b', 'c']; } 
      }); 
     }) 
    ); 

    describe('Initial state', function() { 
     it('should instantiate the controller properly', function() { 
      expect(Ctrl).not.toBeUndefined(); 
     }); 

     it('should initialize its values properly', function() { 

     }); 
    }); 

}); 

这样,茉莉不搜索提供商了,因为你已经注入,都应该被那些需要提供的项目。它的工作原理,但我相信它可以做一个更好的方式...

+0

您需要加载引导程序模块('ui.bootstrap')或者('ui.bootstrap.modal')。试着告诉我。另外一个老虎总是帮助。 –

+0

同样的事情。增加了依赖关系,但同样的错误不断弹出控制台窗口。任何解决方案什么触发它?我试过[这里](http://plnkr.co/edit/OuBIcvbe08FqPc6wjyBq?p=preview),它工作正常,但在我的应用程序的左侧一步,它是在控制台发送这个地狱般的错误。 – Eugene

回答

63

我解决这个只是创建模拟modalmodalInstance对象,并验证他们已被我的控制器代码调用。因为modalmodalInstance是第三方库的一部分,所以测试它们是否正常工作不是我们的责任 - 而是测试我们调用库的代码是否正常工作是我们的责任。使用

你的例子:

describe('Controller: modalCtrl', function() { 

    beforeEach(module('myApp')); 

    var Ctrl; 
    var scope; 
    var modalInstance; 

    // Initialize the controller and a mock scope 
    beforeEach(inject(
    function ($controller, $rootScope) {  // Don't bother injecting a 'real' modal 
     scope = $rootScope.$new(); 
     modalInstance = {     // Create a mock object using spies 
     close: jasmine.createSpy('modalInstance.close'), 
     dismiss: jasmine.createSpy('modalInstance.dismiss'), 
     result: { 
      then: jasmine.createSpy('modalInstance.result.then') 
     } 
     }; 
     Ctrl = $controller('modalCtrl', { 
     $scope: scope, 
     $modalInstance: modalInstance, 
     itemArray: function() { return ['a', 'b', 'c']; } 
     }); 
    }) 
); 

    describe('Initial state', function() { 
    it('should instantiate the controller properly', function() { 
     expect(Ctrl).not.toBeUndefined(); 
    }); 

    it('should close the modal with result "true" when accepted', function() { 
     scope.accept(); 
     expect(modalInstance.close).toHaveBeenCalledWith(true); 
    }); 

    it('should close the modal with result "false" when rejected', function() { 
     scope.reject(); 
     expect(modalInstance.close).toHaveBeenCalledWith(false); 
    }); 
    }); 
}); 

这样,我们并不真正需要的角UI对象和我们的单元测试任何依赖很不错,隔离。

+0

感谢您的回答,我喜欢它。我一直在努力尝试以一种很好的方式来测试我的模态,我认为这很好地处理了它! –

+0

这是正确的。添加不要期望$ modalInstance在一个人的测试中可用于注入器,因为它应该是期望uiBootstrap模块的其他服务的这一点,因为$ modalInstance是使用$ modal服务的新模块的实例化( *可用于注射器)。 –

+1

辉煌,它像一个魅力。 – codeepic

2

+1对于fiznool的回答。这是正确的,应该选择..

我想说明一件事,但它是不可维护的,它在这里介绍。

由于这是角度,我建议使用它..

angular.module('...').service('$modalInstance', function(){ 
    ... define spies and such 
}) 

会使你的代码更加模块化和通用。 简单spec下上述内容添加文件的地方,并确保它包括在你karma.conf如果你想确保它只会加载在特定的测试

,只是给它一个独特的模块名称,并将其添加到module调用在beforeEach

6

相反的:

modalInstance = {     // Create a mock object using spies 
 
    close: jasmine.createSpy('modalInstance.close'), 
 
    dismiss: jasmine.createSpy('modalInstance.dismiss'), 
 
    result: { 
 
    then: jasmine.createSpy('modalInstance.result.then') 
 
    } 
 
};

这可以写成:

modalInstance = jasmine.createSpyObj('modalInstance', ['close', 'dismiss', 'result.then']);

还没有$ modalInstance现在$是uibModalInstance所以每一个 “modalInstance” 以上应以 “uibModalInstance” 取代

+0

+1用于更新$ uibModalInstance。显然这在2015年10月中旬左右发生了变化,当时它们从0.14.3移至1.0.0。 –