在角度指令单元测试中模拟控制器实例化

Ste*_*how 26 javascript unit-testing jasmine angularjs karma-runner

我是单元测试一个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 -->'
        };

    });
Run Code Online (Sandbox Code Playgroud)

这是我将单元测试的一个示例指令,重要的是要从中获取命名控制器.

所以在我的单元测试中

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

    });
});
Run Code Online (Sandbox Code Playgroud)

您可以看到包含3个模块 - 指令,控制器和第三个常量.这被控制器称为依赖性,因此为了将其拉入单元测试,我需要提取依赖性,或者在更糟糕的情况下从控制器获取依赖性.但由于我没有在指令单元测试中对控制器的功能进行单元测试,因此通过包含模块,这似乎是冗余和膨胀的代码.理想情况下,我只想包含我单元测试的模块.

  module('App.Directives.BreadCrumbs');
Run Code Online (Sandbox Code Playgroud)

而不是(添加模块以更多地说明我的观点)

  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
Run Code Online (Sandbox Code Playgroud)

当我们对测试控制器进行单元化时,我们可以模拟完全传递或使用茉莉花间谍传递的服务.我们可以在指令的单元测试中完成同样的事情,所以我不必遵循依赖轨迹吗?

Vad*_*dim 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() {}
            }
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

一旦你这样做,Angular会将你的模拟BreadCrumbsController控制器注入kxBreadcrumbs指令.这样您就不需要将实际控制器和它的依赖性包含在单元测试中.

有关更多信息,请参阅Angular的官方文档: