我正在对Angular指令进行单元测试,并希望以某种方式模拟或存根单元测试中指定控制器的实例化。
首先,我想一些代码......
'use strict';
angular.module('App.Directives.BreadCrumbs', [])
.directive('kxBreadcrumbs', function () {
return {
restrict: 'E',
controller: 'BreadCrumbsController',
template:
'<!-- Breadcrumbs Directive HTML -->' +
'<ol class="breadcrumb">' +
' <li ng-repeat="crumb in crumbPath">' +
' <a ng-class="{true: \'disable\', false: \'\'}[crumb.last]" href="{{crumb.href}}" ng-click="updateCrumb(crumb.name)">{{crumb.name}}</a>' +
' </li>' +
'</ol>' +
'<!-- End of Breadcrumbs Driective HTML -->'
};
});
这是我将单元测试的一个示例指令,重要的是要从中获取命名控制器。
所以在我的单元测试中
'use strict';
describe('Directives: Breadcrumbs', function () {
var//iable declarations
elm,
scope,
$rootScope
;
beforeEach(function () {
module('App.Directives.BreadCrumbs');
module('App.Controllers.BreadCrumbs');
module('App.Constants'); // <--- Comes from the controller dependancy
});
beforeEach(inject(function (_$rootScope_, $compile) {
$rootScope = _$rootScope_;
scope = $rootScope.$new();
elm = angular.element('<kx-breadcrumbs></kx-breadcrumbs>');
$compile(elm)(scope);
scope.$apply();
}));
it('Should create the breadcrumbs template', function () {
scope.crumbPath = [{name: 'home', href: '/'},{name: 'coffee', href: '/coffee'},{name: 'milk', href: '/milk'}];
scope.$apply();
var listItem = $(elm).find('li');
expect(listItem.length).toBe(3);
expect($(listItem).text()).toContain('home');
expect($(listItem).text()).toContain('coffee');
expect($(listItem).text()).toContain('milk');
});
});
你可以看到包含3个模块 - 指令,控制器和第三个常量。这被控制器称为依赖性,因此为了将其拉入单元测试,我需要提取依赖性,或者在更糟糕的情况下从控制器获取依赖性。但由于我没有在指令单元测试中对控制器的功能进行单元测试,因此通过包含模块,这似乎是冗余和膨胀的代码。理想情况下,我只想包含我单元测试的模块。
module('App.Directives.BreadCrumbs');
而不是(添加的模块更能说明我的观点)
module('App.Directives.BreadCrumbs');
module('App.Controllers.BreadCrumbs');
module('App.Constants'); // <--- Comes from the controller dependancy
module('App.Service.SomeService'); // <--- Comes from the controller dependancy
module('App.Service.SomeOtherService'); // <--- Comes from the SomeService dependancy
当我们对测试控制器进行单元化时,我们可以模拟完全传递或使用茉莉花间谍传递的服务。我们可以在指令的单元测试中完成同样的事情,所以我不必遵循依赖轨迹吗?
答案 0 :(得分:39)
您可以在模块配置块中使用$controllerProvider.register()
为控制器创建模拟,$provide.provider()
,$provide.factory()
,$provide.service()
和$provide.value()
用于提供商,工厂和服务:
<强>的JavaScript 强>
beforeEach(function () {
module('App.Directives.BreadCrumbs', function($provide, $controllerProvider) {
$controllerProvider.register('BreadCrumbsController', function($scope) {
// Controller Mock
});
$provide.factory('someService', function() {
// Service/Factory Mock
return {
doSomething: function() {}
}
});
});
});
一旦这样做,Angular会将模拟BreadCrumbsController
控制器注入kxBreadcrumbs
指令。这样,您就不需要将真实控制器及其依赖性包含在单元测试中。
有关更多信息,请参阅Angular的官方文档: