通过sidewaffle测试控制器中的私有方法和提供的模板

时间:2015-08-10 17:03:18

标签: javascript angularjs unit-testing

我一直在学习如何测试我用角度来写的应用程序而且我感到困惑,因为它似乎有一些相互对立的东西。我试着跟随John Papa的style guide,以便我基本上使用Sidewaffle模板。目前看来,建议的模板和可测试性相互对立。

样式指南说有一个

  

激活()

控制器中的

方法,它可以看到控制器的启动逻辑,如here所示。但是,一般测试指南说不应该测试私有方法。我有机会在提供的示例中测试activate()方法的结果,因为它将通过

传递
  

vm.avengers

变量。在他的Pluralsight videos中,他使用common.activatecontroller()方法,他使用

  

$ q.all()

结合承诺,以便您可以在控制器激活阶段轻松调用许多功能。假设我有一个没有结果的函数可以通过vm传递,例如发布消息给WebApi来验证用户并获取令牌并将其设置为标题,或类似的东西。这是一个例子(服务没有注入,只是一个例子):

在下面的控制器中,唯一的业务逻辑是,当实例化控制器时,activate()方法调用调用OAuthenticationService.authenticate()方法的func1()方法。从测试的角度来看,服务是否被调用很重要。如何测试?

Here是一个非常相似的问题,其中一个答案表明我应该使用这样的关键字:

  

this.activate()

但是评论说它没有使用ControllerAs语法。我正在遵循ControllerAs语法。

当我在authenticate方法上使用spy为服务创建模拟时,测试表明我没有被调用,我认为由于该方法是私有的。

我没有想法......

提前感谢您的帮助!

示例

(function () {
    'use strict';

    angular
        .module('app')
        .controller('controller', controller);

    controller.$inject = ['$location']; 

    function controller($location) {
        /* jshint validthis:true */
        var vm = this;
        vm.title = 'controller';

        activate();

        function activate() {

            func1();

        }

        function func1() {

            OAuthAuthenticateService.authenticate(user).then(function() {

                //setting up headers and other stuff, nothin will be part of $scope or vm;

            });

        }
    }
})();

原始代码

(function () {
    'use strict';

    var controllerId = 'requestAuthorizationController';

    angular
        .module('myapp')
        .controller(controllerId, requestAuthorizationController);

    requestAuthorizationController.$inject = ['$rootScope',
                                                '$scope',
                                                'requestAuthorizationService'
                                                'Restangular'];

    function requestAuthorizationController($rootScope,
                                            $scope,
                                            requestAuthorizationService
                                            Restangular) {
        /* jshint validthis:true */
        var vm = this;

//other business logic

        activate();

        function activate() {

            requestAuthorization();

        }

        function requestAuthorization() {

            vm.fired = undefined;

            requestAuthorizationService.getDummy();

        }
    }
})();

茉莉花测试

'use strict';

describe('RequestAuthenticationController Specification', function () {

    var RestangularProviderMock,
        localStorageServiceProvider,
        $httpProvider,
        requestAuthorizationController,
        requestAuthorizationServiceMock,
        $rootScope;

    //modules
    beforeEach(function() {

        angular.module('dilib.layout', []);
        angular.module('http-auth-interceptor', []);

    });


    //providers
    beforeEach(function () {

        module('dilib', function(RestangularProvider, _localStorageServiceProvider_, _$httpProvider_, $provide) {

            RestangularProviderMock = RestangularProvider;
            localStorageServiceProvider = _localStorageServiceProvider_;
            $httpProvider = _$httpProvider_;

            $provide.service('requestAuthorizationService', function() {
                this.getDummy = jasmine.createSpy('getDummy').and.callFake(function(num) {
                });
            });
        });

    });

    //to crank up the providers
    beforeEach(inject());

    beforeEach(inject(function (_$rootScope_, _$controller_, _requestAuthorizationService_) {

        $rootScope = _$rootScope_;
        requestAuthorizationController = _$controller_;

        requestAuthorizationServiceMock = _requestAuthorizationService_;

    }));



     describe('requestAuthorization function', function() {

         it('RequestAuthorizationService.getDummy() is called', function() {

            $rootScope.$digest();
            expect(requestAuthorizationServiceMock.getDummy).toHaveBeenCalled();

        });

    });


});

2 个答案:

答案 0 :(得分:0)

我认为我所采用的整个方法都是错误的。我在控制器中有太多的业务逻辑。根据{{​​3}}文章和其他文章,我必须尽可能地减少控制器中的业务逻辑,并将其置于服务公共方法中。如果我遵循这个规则,那么就不需要私有方法。但是,问题仍然与

有关
  

激活()

方法。它足以测试执行函数的结果,即填充的视图模型?我想,答案是肯定的。

目前我专注于是否正确填充了视图模型变量,并且我将业务逻辑重构为服务。

在我看来,编写工作非常容易,但很难测试代码,而不是工作且易于测试代码。

故事的另一个方面是我作为测试员工作了10年,在测试的许多方面都有很好的经验。但是现在,我只是在摸索如何在可测试/测试驱动的开发方式上编写代码。 :)

答案 1 :(得分:0)

因此,在John Papa的风格指南中,activate()方法是一种抽象。如果您在构造函数方法中进行了大量设置,则将其抽象为activate()方法。然后你的构造函数是干净的。我不确定你发布的代码中有多少价值。

另外,您应该只对单元的API,外部接口进行单元测试。因此,对于控制器,视图中的操作调用的属性和方法。