应该如何运行块的角度单元测试与处理? [英] How should the run block be dealt with in Angular unit tests?

查看:297
本文介绍了应该如何运行块的角度单元测试与处理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的理解是,当你加载模块中的角单元测试中,运行块被调用。

我认为,如果你正在测试一个组件,你不会想同时测试运行块,因为的单元测试应该只测试一个的单位的。是真的吗?

如果是这样,有没有办法prevent的运行块从运行?我的研究使我认为,答案是不,那运行块总是当模块被加载,但也许有覆盖此方式运行。如果没有,我怎么会测试运行阻止?

生成块:

 函数run(验证,$饼干,$ rootScope){
  $ rootScope.user = {};
  Auth.getCurrentUser();
}

Auth.getCurrentUser:

  getCurrentUser:功能(){
  //用户登录
  如果(Object.keys($ rootScope.user)。长度大于0){
    返回$ q.when($ rootScope.user);
  }
  //用户登录,但页面已被刷新和$ rootScope.user丢失
  如果($ cookies.get('用户id')){
    返回$ http.get('/当前用户)
      。然后(功能(响应){
        angular.copy(response.data,$ rootScope.user);
        返回$ rootScope.user;
      })
    ;
  }
  //用户没有登录
  其他{
    返回$ q.when({});
  }
}

auth.factory.spec.js

 描述('验证工厂,函数(){
  VAR验证,$ httpBackend,$ rootScope,$饼干,$ Q;
  VAR用户= {
    用户名:'A',
    密码:'密码',
  };
  VAR响应= {
    _id:1,
    本地:{
      用户名:'A',
      角色:用户
    }
  };  功能isPromise(EL){
    返回!! EL $$状态。
  }  beforeEach(模块('平均起动,ngCookies','模板'));
  beforeEach(注(功能(_Auth_,_ $ httpBackend_,_ $ rootScope_,_ $ cookies_,_ $ Q_){
    验证= _Auth_;
    $ httpBackend = _ $ httpBackend_;
    $ rootScope = _ $ rootScope_;
    $饼干= _ $ cookies_;
    $ Q = _ $ Q_;
  }));
  afterEach(函数(){
    $ httpBackend.verifyNoOutstandingExpectation();
    $ httpBackend.verifyNoOutstandingRequest();
  });  它('#注册',函数(){
    $ rootScope.user = {};
    $ httpBackend.expectPOST('/用户,用户).respond(响应);
    spyOn(角,复制)and.callThrough()。
    spyOn($饼干,'放')and.callThrough()。
    VAR retVal的= Auth.signup(用户);
    $ httpBackend.flush();
    期待(angular.copy).toHaveBeenCalledWith(响应,$ rootScope.user);
    期待($ cookies.put).toHaveBeenCalledWith('用户id',1);
    期待(isPromise(retVal的))TOBE(真)。
  });  它('#登录',函数(){
    $ rootScope.user = {};
    $ httpBackend.expectPOST('/登录,用户).respond(响应);
    spyOn(角,复制)and.callThrough()。
    spyOn($饼干,'放')and.callThrough()。
    VAR retVal的= Auth.login(用户);
    $ httpBackend.flush();
    期待(angular.copy).toHaveBeenCalledWith(响应,$ rootScope.user);
    期待($ cookies.put).toHaveBeenCalledWith('用户id',1);
    期待(isPromise(retVal的))TOBE(真)。
  });  它('#注销',函数(){
    $ httpBackend.expectGET('/注销)响应()。
    spyOn(角,复制)and.callThrough()。
    spyOn($饼干,'删除');
    Auth.logout();
    $ httpBackend.flush();
    期待(angular.copy).toHaveBeenCalledWith({} $ rootScope.user);
    期待($ cookies.remove).toHaveBeenCalledWith('用户id');
  });  描述('#getCurrentUser',函数(){
    它('用户已经登录',函数(){
      $ rootScope.user =响应;
      spyOn($ Q,'当')and.callThrough()。
      变种retVal的= Auth.getCurrentUser();
      期待($ q.when).toHaveBeenCalledWith($ rootScope.user);
      期待(isPromise(retVal的))TOBE(真)。
    });
    它('用户已经登录,但页面已经被刷新',函数(){
      $ cookies.put('用户id',1);
      。$ httpBackend.expectGET('/当前用户)响应(响应);
      spyOn(角,复制)and.callThrough()。
      变种retVal的= Auth.getCurrentUser();
      $ httpBackend.flush();
      期待(angular.copy).toHaveBeenCalledWith(响应,$ rootScope.user);
      期待(isPromise(retVal的))TOBE(真)。
    });
    它(用户没有登录功能(){
      $ rootScope.user = {};
      $ cookies.remove('用户id');
      spyOn($ Q,'当')and.callThrough()。
      变种retVal的= Auth.getCurrentUser();
      期待($ q.when).toHaveBeenCalledWith({});
      期待(isPromise(retVal的))TOBE(真)。
    });
  });
});


尝试1:

  beforeEach(模块('平均起动,ngCookies','模板'));
beforeEach(注(功能(_Auth_,_ $ httpBackend_,_ $ rootScope_,_ $ cookies_,_ $ Q_){
  验证= _Auth_;
  $ httpBackend = _ $ httpBackend_;
  $ rootScope = _ $ rootScope_;
  $饼干= _ $ cookies_;
  $ Q = _ $ Q_;
}));
beforeEach(函数(){
  spyOn(验证,'getCurrentUser');
});
afterEach(函数(){
  期待(Auth.getCurrentUser).to​​HaveBeenCalled();
  $ httpBackend.verifyNoOutstandingExpectation();
  $ httpBackend.verifyNoOutstandingRequest();
});

这是行不通的。在运行加载模块时块运行,因此 Auth.getCurrentUser()设置间谍之前被称为了。

 来一直呼吁的预期间谍getCurrentUser。


尝试二:

  beforeEach(注(功能(_Auth_,_ $ httpBackend_,_ $ rootScope_,_ $ cookies_,_ $ Q_){
  验证= _Auth_;
  $ httpBackend = _ $ httpBackend_;
  $ rootScope = _ $ rootScope_;
  $饼干= _ $ cookies_;
  $ Q = _ $ Q_;
}));
beforeEach(函数(){
  spyOn(验证,'getCurrentUser');
});
beforeEach(模块('平均起动,ngCookies','模板'));
afterEach(函数(){
  期待(Auth.getCurrentUser).to​​HaveBeenCalled();
  $ httpBackend.verifyNoOutstandingExpectation();
  $ httpBackend.verifyNoOutstandingRequest();
});

这不起作用,因为验证不可被装载我的应用程序模块前被注入。

 错误:[$喷油器:unpr]未知提供商:AuthProvider<  - 验证


尝试3:

正如你所看到的,这里有一个鸡有蛋的问题。我需要注入验证,并成立了间谍加载模块之前,但我不能,因为验证不可被加载模块之前注入。

的博客文章中提到的鸡有蛋的问题,并提供了一​​个有趣的潜在的解决方案。作者认为,我应该使用手动创建我的验证服务 $提供前的我加载的我的模块。由于我在创建服务,不注射,我能做到这一点在加载模块之前,我可以建立间谍。然后加载模块时,它会使用这个创建模拟服务。

下面是他的榜样code:

 描述(示例,函数(){
    VAR loggingService;
    beforeEach(函数(){
        模块(示例,函数($提供){
            $ provide.value('loggingService',{
                启动:jasmine.createSpy()
            });
        });
        注(功能(_loggingService_){
            loggingService = _loggingService_;
        });
    });
    它('应该启动日志服务',函数(){
        期待(loggingService.start).toHaveBeenCalled();
    });
});

这里的问题是,我需要我的验证服务!我只希望使用的运行块模拟之一;我需要真正的验证服务在其他地方,所以我可以测试它。

我想,我可以使用 $提供创建实际的验证服务,但那种感觉是错误的。


最后一个问题 - 不管是什么code我最终使用来处理这个运行块的问题,有没有办法对我来说,解压出来,所以我不要'T必须把它重新写我的每个规格文件?我能想到的唯一办法做到这一点是使用某种全球性的功能。


auth.factory.js

 
  .module('平均起动器)
  .factory('验证',验证)
;功能验证($ HTTP,$状态,$窗口,$饼干,$ Q $ rootScope){
  返回{
    注册:功能(用户){
      返回$ HTTP
        。员额('/用户,用户)
        。然后(功能(响应){
          angular.copy(response.data,$ rootScope.user);
          $ cookies.put('用户id',response.data._id);
          $ state.go('家');
        })
      ;
    },
    登录:功能(用户){
      返回$ HTTP
        。员额('/登录,用户)
        。然后(功能(响应){
          angular.copy(response.data,$ rootScope.user);
          $ cookies.put('用户id',response.data._id);
          $ state.go('家');
        })
      ;
    },
    注销:功能(){
      $ HTTP
        获得('/注销)
        。然后(函数(){
          angular.copy({},$ rootScope.user);
          $ cookies.remove('用户id');
          $ state.go('家');
        })
        .catch(函数(){
          的console.log('问题退出。');
        })
      ;
    },
    getCurrentUser:功能(){
      //用户登录
      如果(Object.keys($ rootScope.user)。长度大于0){
        返回$ q.when($ rootScope.user);
      }
      //用户登录,但页面已被刷新和$ rootScope.user丢失
      如果($ cookies.get('用户id')){
        返回$ http.get('/当前用户)
          。然后(功能(响应){
            angular.copy(response.data,$ rootScope.user);
            返回$ rootScope.user;
          })
        ;
      }
      //用户没有登录
      其他{
        返回$ q.when({});
      }
    }
  };
}


编辑 - 失败的尝试+成功的尝试:

  beforeEach(模块('权威性'));
beforeEach(注(功能(_Auth_){
  验证= _Auth_;
  spyOn(验证,'requestCurrentUser');
}));
beforeEach(模块('平均起动,ngCookies','模板'));
beforeEach(注(功能(_Auth_,_ $ httpBackend_,_ $ rootScope_,_ $ cookies_,_ $ Q_){
  //验证= _Auth_;
  $ httpBackend = _ $ httpBackend_;
  $ rootScope = _ $ rootScope_;
  $饼干= _ $ cookies_;
  $ Q = _ $ Q_;
}));
// beforeEach(函数(){
// spyOn(AUTH,'getCurrentUser');
//});
afterEach(函数(){
  期待(Auth.getCurrentUser).to​​HaveBeenCalled();
  $ httpBackend.verifyNoOutstandingExpectation();
  $ httpBackend.verifyNoOutstandingRequest();
});

我不知道为什么,这是行不通的(独立的问题,使用两次)。

我试图绕过不必使用 $提供作为最初觉得哈克/怪我。多一些,虽然思考之后,我现在觉得 $提供是好的,那下面的建议,使用模拟AUTH 是太棒了!无论为我工作。

auth.factory.spec.js 我刚装了 AUTH 模块(我称之为 AUTH ,而不是均AUTH ),而无需加载均首发 。这不具有运行块问题,因为模块没有在运行块code,但它可以让我来测试我的验证工厂。在其他地方,这个作品:

  beforeEach(模块('均首发','模板',函数($提供){
  $ provide.value('验证',{
    requestCurrentUser:jasmine.createSpy()
  });
}));

一样美妙的模拟AUTH 解决方案:

auth.factory.mock.js

 
  .module('模拟身份验证,[])
  .factory('验证',验证)
;功能验证(){
  返回{
    requestCurrentUser:jasmine.createSpy()
  };
}

user.service.spec.js

  beforeEach(模块('平均起动,模拟身份验证','模板'));


解决方案

  

我的理解是,当你加载角度单位你的模块
  测试中,运行块被调用。


正确的。


  

我认为,如果你正在测试一个组件,你不会想
  同时测试运行段,因为单元测试
  应该只是测试一个单元。是真的吗?


也是正确的,因为现在你正在有效地测试验证和你的运行程序段,整合并没有从另一个隔离。


  

如果是这样,有没有办法prevent从运行run块?我的
  研究使我认为,答案是不,而且运行
  块始终运行时模块被加载,但也许有一种方法
  重写此。如果没有,我怎么会测试运行块?


作为实施,没有你不能prevent运行运行块。然而,有一些小的重构你的问题最终是模块化的一个仍然可能。如果不能够看到您的模块声明,我会想象它看起来是这样的:

  angular.module('平均起动器',['ngCookies'])  .factory('验证',函数($饼干){
    ...
  });  .RUN(功能(验证,$ rootScope){
    ...
  });

此模式可以分成模块以支持可测性(和模块可重用):

  angular.module('平均-auth的',['ngCookies'])  .factory('验证',函数(){
    ...
  });angular.module('平均起动器',['平均-AUTH'])  .RUN(功能(验证,$ rootScope){
    ...
  });

这现在允许您通过均AUTH 模块加载只能进到隔离测试你的验证工厂其试验。

虽然这解决了您的运行块与单元测试干扰了验证,你仍然面临着嘲讽的问题 Auth.getCurrentUser <问题/ code>,以便隔离测试运行块。你引用的博客文章是正确的在你应该寻找利用模块的配置阶段存根上在运行阶段使用依赖/间谍。因此,在您的测试:

 模块('平均起动器',函数($提供){
  $ provide.value('验证',{
    getCurrentUser:jasmine.createSpy()
  });
});

至于你的最后一个问题,您可以通过声明为模块创建可重用的嘲弄。例如,如果你想创建一个可重复使用的模拟工厂验证将其定义在单元测试之前加载一个单独的文件:

  angular.module('模拟身份验证,[]) .factory('验证',函数(){
   返回{
     getCurrentUser:jasmine.createSpy()
   };
 });

然后加载它到任何模块以后你的测试中,你需要它,因为角度将覆盖具有相同名称的任何服务:

 模块('平均起动器,模拟AUTH');

My understanding is that when you load your module in Angular unit tests, the run block gets called.

I'd think that if you're testing a component, you wouldn't want to simultaneously be testing the run block, because unit tests are supposed to just test one unit. Is that true?

If so, is there a way to prevent the run block from running? My research leads me to think that the answer is "no", and that the run block always runs when the module is loaded, but perhaps there's a way to override this. If not, how would I test the run block?

Run block:

function run(Auth, $cookies, $rootScope) {
  $rootScope.user = {};
  Auth.getCurrentUser();
}

Auth.getCurrentUser:

getCurrentUser: function() {
  // user is logged in
  if (Object.keys($rootScope.user).length > 0) {
    return $q.when($rootScope.user);
  }
  // user is logged in, but page has been refreshed and $rootScope.user is lost
  if ($cookies.get('userId')) {
    return $http.get('/current-user')
      .then(function(response) {
        angular.copy(response.data, $rootScope.user);
        return $rootScope.user;
      })
    ;
  }
  // user isn't logged in
  else  {
    return $q.when({});
  }
}

auth.factory.spec.js

describe('Auth Factory', function() {
  var Auth, $httpBackend, $rootScope, $cookies, $q;
  var user = {
    username: 'a',
    password: 'password',
  };
  var response = {
    _id: 1,
    local: {
      username: 'a',
      role: 'user'
    }
  };

  function isPromise(el) {
    return !!el.$$state;
  }

  beforeEach(module('mean-starter', 'ngCookies', 'templates'));
  beforeEach(inject(function(_Auth_, _$httpBackend_, _$rootScope_, _$cookies_, _$q_) {
    Auth = _Auth_;
    $httpBackend = _$httpBackend_;
    $rootScope = _$rootScope_;
    $cookies = _$cookies_;
    $q = _$q_;
  }));
  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  it('#signup', function() {
    $rootScope.user = {};
    $httpBackend.expectPOST('/users', user).respond(response);
    spyOn(angular, 'copy').and.callThrough();
    spyOn($cookies, 'put').and.callThrough();
    var retVal = Auth.signup(user);
    $httpBackend.flush();
    expect(angular.copy).toHaveBeenCalledWith(response, $rootScope.user);
    expect($cookies.put).toHaveBeenCalledWith('userId', 1);
    expect(isPromise(retVal)).toBe(true);
  });

  it('#login', function() {
    $rootScope.user = {};
    $httpBackend.expectPOST('/login', user).respond(response);
    spyOn(angular, 'copy').and.callThrough();
    spyOn($cookies, 'put').and.callThrough();
    var retVal = Auth.login(user);
    $httpBackend.flush();
    expect(angular.copy).toHaveBeenCalledWith(response, $rootScope.user);
    expect($cookies.put).toHaveBeenCalledWith('userId', 1);
    expect(isPromise(retVal)).toBe(true);
  });

  it('#logout', function() {
    $httpBackend.expectGET('/logout').respond();
    spyOn(angular, 'copy').and.callThrough();
    spyOn($cookies, 'remove');
    Auth.logout();
    $httpBackend.flush();
    expect(angular.copy).toHaveBeenCalledWith({}, $rootScope.user);
    expect($cookies.remove).toHaveBeenCalledWith('userId');
  });

  describe('#getCurrentUser', function() {
    it('User is logged in', function() {
      $rootScope.user = response;
      spyOn($q, 'when').and.callThrough();
      var retVal = Auth.getCurrentUser();
      expect($q.when).toHaveBeenCalledWith($rootScope.user);
      expect(isPromise(retVal)).toBe(true);
    });
    it('User is logged in but page has been refreshed', function() {
      $cookies.put('userId', 1);
      $httpBackend.expectGET('/current-user').respond(response);
      spyOn(angular, 'copy').and.callThrough();
      var retVal = Auth.getCurrentUser();
      $httpBackend.flush();
      expect(angular.copy).toHaveBeenCalledWith(response, $rootScope.user);
      expect(isPromise(retVal)).toBe(true);
    });
    it("User isn't logged in", function() {
      $rootScope.user = {};
      $cookies.remove('userId');
      spyOn($q, 'when').and.callThrough();
      var retVal = Auth.getCurrentUser();
      expect($q.when).toHaveBeenCalledWith({});
      expect(isPromise(retVal)).toBe(true);
    });
  });
});


Attempt 1:

beforeEach(module('mean-starter', 'ngCookies', 'templates'));
beforeEach(inject(function(_Auth_, _$httpBackend_, _$rootScope_, _$cookies_, _$q_) {
  Auth = _Auth_;
  $httpBackend = _$httpBackend_;
  $rootScope = _$rootScope_;
  $cookies = _$cookies_;
  $q = _$q_;
}));
beforeEach(function() {
  spyOn(Auth, 'getCurrentUser');
});
afterEach(function() {
  expect(Auth.getCurrentUser).toHaveBeenCalled();
  $httpBackend.verifyNoOutstandingExpectation();
  $httpBackend.verifyNoOutstandingRequest();
});

This doesn't work. The run block is run when the module is loaded, so Auth.getCurrentUser() is called before the spy is set up.

Expected spy getCurrentUser to have been called.


Attempt 2:

beforeEach(inject(function(_Auth_, _$httpBackend_, _$rootScope_, _$cookies_, _$q_) {
  Auth = _Auth_;
  $httpBackend = _$httpBackend_;
  $rootScope = _$rootScope_;
  $cookies = _$cookies_;
  $q = _$q_;
}));
beforeEach(function() {
  spyOn(Auth, 'getCurrentUser');
});
beforeEach(module('mean-starter', 'ngCookies', 'templates'));
afterEach(function() {
  expect(Auth.getCurrentUser).toHaveBeenCalled();
  $httpBackend.verifyNoOutstandingExpectation();
  $httpBackend.verifyNoOutstandingRequest();
});

This doesn't work because Auth isn't available to be injected before my app module is loaded.

Error: [$injector:unpr] Unknown provider: AuthProvider <- Auth


Attempt 3:

As you can see, there's a chicken-egg problem here. I need to inject Auth and set up the spy before the module is loaded, but I can't because Auth isn't available to be injected before the module is loaded.

This blog posts mentions the chicken-egg problem and provides an interesting potential solution. The author proposes that I should create my Auth service manually using $provide before I load my module. Since I'm creating the service, not injecting it, I could do it before the module is loaded, and I could set up the spy. Then when the module is loaded, it'd use this created mock service.

Here is his example code:

describe('example', function () {
    var loggingService;
    beforeEach(function () {
        module('example', function ($provide) {
            $provide.value('loggingService', {
                start: jasmine.createSpy()
            });
        });
        inject(function (_loggingService_) {
            loggingService = _loggingService_;
        });
    });
    it('should start logging service', function() {
        expect(loggingService.start).toHaveBeenCalled();
    });
});

The problem with this, is that I need my Auth service! I only would want to use the mock one for the run block; I need my real Auth service elsewhere so I could test it.

I guess that I could create the actual Auth service using $provide, but that feels wrong.


Final question - for whatever code I end up using to deal with this run block problem, is there a way for me to extract it out so I don't have to re-write it for each of my spec files? The only way I could think to do it would be to use some sort of global function.


auth.factory.js

angular
  .module('mean-starter')
  .factory('Auth', Auth)
;

function Auth($http, $state, $window, $cookies, $q, $rootScope) {
  return {
    signup: function(user) {
      return $http
        .post('/users', user)
        .then(function(response) {
          angular.copy(response.data, $rootScope.user);
          $cookies.put('userId', response.data._id);
          $state.go('home');
        })
      ;
    },
    login: function(user) {
      return $http
        .post('/login', user)
        .then(function(response) {
          angular.copy(response.data, $rootScope.user);
          $cookies.put('userId', response.data._id);
          $state.go('home');
        })
      ;
    },
    logout: function() {
      $http
        .get('/logout')
        .then(function() {
          angular.copy({}, $rootScope.user);
          $cookies.remove('userId');
          $state.go('home');
        })
        .catch(function() {
          console.log('Problem logging out.');
        })
      ;
    },
    getCurrentUser: function() {
      // user is logged in
      if (Object.keys($rootScope.user).length > 0) {
        return $q.when($rootScope.user);
      }
      // user is logged in, but page has been refreshed and $rootScope.user is lost
      if ($cookies.get('userId')) {
        return $http.get('/current-user')
          .then(function(response) {
            angular.copy(response.data, $rootScope.user);
            return $rootScope.user;
          })
        ;
      }
      // user isn't logged in
      else  {
        return $q.when({});
      }
    }
  };
}


Edit - failed attempt + successful attempt:

beforeEach(module('auth'));
beforeEach(inject(function(_Auth_) {
  Auth = _Auth_;
  spyOn(Auth, 'requestCurrentUser');
}));
beforeEach(module('mean-starter', 'ngCookies', 'templates'));
beforeEach(inject(function(_Auth_, _$httpBackend_, _$rootScope_, _$cookies_, _$q_) {
  // Auth = _Auth_;
  $httpBackend = _$httpBackend_;
  $rootScope = _$rootScope_;
  $cookies = _$cookies_;
  $q = _$q_;
}));
// beforeEach(function() {
//   spyOn(Auth, 'getCurrentUser');
// });
afterEach(function() {
  expect(Auth.getCurrentUser).toHaveBeenCalled();
  $httpBackend.verifyNoOutstandingExpectation();
  $httpBackend.verifyNoOutstandingRequest();
});

I'm not sure why this wouldn't work (independent of the problem with using inject twice).

I was trying to get around having to use $provide as that initially felt hacky/weird to me. After thinking about it some more though, I now feel that $provide is fine, and that following your suggestion to use mock-auth is fantastic!!! Both worked for me.

In auth.factory.spec.js I just loaded the auth module (I'm calling it auth, not mean-auth) without loading mean-starter. This doesn't have the run block problem because that module doesn't have the run block code, but it allows me to test my Auth factory. Elsewhere, this works:

beforeEach(module('mean-starter', 'templates', function($provide) {
  $provide.value('Auth', {
    requestCurrentUser: jasmine.createSpy()
  });
}));

As does the fantastic mock-auth solution:

auth.factory.mock.js

angular
  .module('mock-auth', [])
  .factory('Auth', Auth)
;

function Auth() {
  return {
    requestCurrentUser: jasmine.createSpy()
  };
}

user.service.spec.js

beforeEach(module('mean-starter', 'mock-auth', 'templates'));

解决方案

My understanding is that when you load your module in Angular unit tests, the run block gets called.

Correct.

I'd think that if you're testing a component, you wouldn't want to simultaneously be testing the run block, because unit tests are supposed to just test one unit. Is that true?

Also correct, in that right now you are effectively testing the integration of Auth and your run block, and there is no isolation of one from the other.

If so, is there a way to prevent the run block from running? My research leads me to think that the answer is "no", and that the run block always runs when the module is loaded, but perhaps there's a way to override this. If not, how would I test the run block?

As implemented, no you cannot prevent the run block from running. However, it remains possible with some minor refactoring as your question is ultimately one of modularisation. Without being able to see your module declaration, I would imagine it looks something like this:

angular.module('mean-starter', ['ngCookies'])

  .factory('Auth', function($cookies) {
    ...
  });

  .run(function(Auth, $rootScope) {
    ...
  });

This pattern can be broken into modules to support testability (and module reusability):

angular.module('mean-auth', ['ngCookies'])

  .factory('Auth', function() {
    ...
  });

angular.module('mean-starter', ['mean-auth'])

  .run(function(Auth, $rootScope) {
    ...
  });

This now allows you to test your Auth factory in isolation by loading the mean-auth module only into its test.

While this solves the problem of your run block interfering with your unit tests for Auth, you still face the problem of mocking Auth.getCurrentUser so as to test your run block in isolation. The blog post you referenced is correct in that you should be looking to leverage the configuration stage of the module to stub/spy on dependencies used during the run stage. Therefore, in your test:

module('mean-starter', function ($provide) {
  $provide.value('Auth', {
    getCurrentUser: jasmine.createSpy()
  });
});

As to your final question, you can create reusable mocks by declaring them as modules. For example, if you wanted to create a reusable mock factory for Auth you define it in a separate file loaded prior to your unit tests:

angular.module('mock-auth', [])

 .factory('Auth', function() {
   return {
     getCurrentUser: jasmine.createSpy()
   };
 });

and then load it in your tests subsequent to any module in which you require it, as angular will overwrite any service with the same name:

module('mean-starter', 'mock-auth');

这篇关于应该如何运行块的角度单元测试与处理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆