测试在主模块.run方法内运行的AngularJS代码

时间:2012-11-05 16:46:37

标签: unit-testing angularjs jasmine

所以我开始为我编写的AngularJS应用程序编写单元测试。此应用程序受登录页面保护,因此如果用户名未登录,则除登录页面之外的任何页面的任何请求都将重定向登录页面。这个逻辑是从主模块.run()方法执行的,因为它只需要运行一次,当应用程序启动时,有没有办法测试从主模块.run()方法中执行的代码?我是以下测试代码:

describe('Login Controller', function(){
    'use strict';

    var scope, controller, $httpBackend, $resource, callback;

    beforeEach(module('application'));

    beforeEach(inject(function($injector, $rootScope, $controller, $http, $location, authentication, session) {
        $httpBackend = $injector.get('$httpBackend');
        $httpBackend.expectGET('/api/v1/authentication').respond({status: 'success', data: null});
        $resource = $injector.get('$resource');
        callback = jasmine.createSpy();
        scope = $rootScope.$new();
        controller = new $controller('Login', {
            $scope: scope,
            $http: $http,
            $location: $location,
            authentication: authentication,
            session: session
        });
    }));

    afterEach(function() {
        $httpBackend.verifyrifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it('should verify all default values for controller', function() {
        expect(scope.username).toEqual('');
        expect(scope.password).toEqual('');
        expect(scope.displayApplicationLoad).toEqual(false);
        expect(angular.isFunction(scope.login)).toEqual(true);
        expect(angular.isFunction(scope.logout)).toEqual(true);
        expect(scope.loggedIn).toEqual(false);
        expect(scope.headerTemplate).toEqual('/templates/core/header.html');
        expect(scope.footerTemplate).toEqual('/templates/core/footer.html');
    });
});

问题是主模块.run()方法内部运行的代码没有考虑到

$httpBackend.expectGET('/api/v1/authentication').respond({status: 'success', data: null});

线。我应该将此逻辑放在其他地方,以便我可以对此代码进行单元测试吗?

2 个答案:

答案 0 :(得分:6)

我会将您要测试的所有代码移动到一个服务中,然后将其注入到运行块中。然后,您可以独立测试此服务。此外,您还可以设置模块,以便更灵活地测试依赖于身份验证的其他内容。

答案 1 :(得分:0)

我想我找到了一种测试模块运行方法的方法。这有点hacky但它​​完成了工作。这是我的解决方案:

describe( 'my module', function() {

  var runBlocks;

  beforeEach( function() {
     var myModule = angular.module( 'modules.flow' );

     runBlocks = myModule._runBlocks;
     myModule._runBlocks = [];

     module( 'myModule' );
  } );

  afterEach( function() {
     angular.module( 'modules.flow' )._runBlocks = runBlocks;
  } );

  describe( 'when loaded', function() {

     beforeEach( inject( function( $injector ) {

        // Here you could e.g. configure $httpBackend

        for( var i = 0; i < runBlocks.length; ++i ) {
           $injector.invoke( runBlocks[i] );
        }
     } ) );

     // Tests ...

  } );

} );

首先,我复制为模块定义的所有运行块,并删除运行块的内部列表。然后可以进行运行块成功所需的设置,然后让注入器调用函数。

尽管如此,如果有机会将运行块中的代码提取到适当的服务中,您应该更喜欢这种方式。

更新:添加了缺失的afterEach方法

更新2:修正了对angular.module

的调用