AngularJS覆盖(模拟)单元测试服务

时间:2013-11-16 23:50:37

标签: angularjs

场景非常简单,我正在尝试测试服务A,这取决于服务B,所以我决定在注入服务A之前通过覆盖它来模拟服务B.但是,我也在测试服务B,这是因为被覆盖而不再有效。如何避免这种想法?

申请代码。

angular.module('MyApp.services')
  .factory('serviceB', function(){
    return {
      greeting: function(){ return 'hello'; }
    }
  })
  .factory('serviceA', ['serviceB', function(serviceB){
    return {
      greeting: function(){
        return 'I say: ' + serviceB.greeting();
      }
  });

单元测试:

describe('My app services', function(){

  beforeEach(module('MyApp.services'));

  describe('service A', function(){
      // mock service B
    angular.module('MyApp.services').factory('serviceB', function(){
      return { greeting: function(){ return 'mocked B'; } }
    });

    var serviceA;

    inject(function(_serviceA_){
      serviceA = _serviceA_;
    });

    it('should work', function(){
      var words = serviceA.greeting();
      expect(words).toBe('I say: mocked B');          
    });
  });

  describe('service B'. function(){
    var serviceB;

    inject(function(_serviceB_){
      serviceB = _serviceB_;
    });

    it('should work', function(){
      var words = serviceB.greeting();
      expect(words).toBe('hello');
    });
  });
});

2 个答案:

答案 0 :(得分:10)

您的服务注入应该在beforeEach或作为测试的一部分,否则我认为它们将在测试开始之前发生或根本不发生,例如。

beforeEach(inject(function(_serviceA_){
  serviceA = _serviceA_;
}));

it('should work', inject(function(serviceA){
    var words = serviceA.greeting();
    expect(words).toBe('I say: mocked B');          
}));

要解决您实际问的问题,我建议您做以下两件事之一:

  1. 覆盖注入器中的服务而不是模块

    beforeEach(module(function($provide){
      $provide.value('serviceB', {
        greeting: function(){ return 'mocked B'; }
      });
    }));
    

    请参阅plunker

  2. 使用可在需要时添加的单独模块来覆盖serviceB

    某处(只需要调用一次),将包含模拟版本serviceB

    的新模块定义
    angular.module('MyApp.services.mock', [])
      .factory('serviceB', function(){
        return { greeting: function(){ return 'mocked B'; } }
      });
    

    然后您当前在测试模块中更改服务的位置,使用以下内容将模拟加载到模块顶部。

    beforeEach(module('MyApp.services.mock'));
    

    请参阅plunker

答案 1 :(得分:0)

使用间谍而不是模块覆盖服务,然后,当您测试(单元测试)服务A时,您只测试服务A,这意味着您可以模拟(间谍)服务B并假设您有服务测试B并且正在工作。

单元测试:

describe('My app services', function(){

  beforeEach(module('MyApp.services'));

  describe('service A', function(){
    var serviceA, serviceB;

    inject(function(_serviceA_, _serviceB_){
      serviceA = _serviceA_;
      serviceB = _serviceB_;
    });

    it('should work', function(){
      spyOn(serviceB, 'greeting').and.returnValue('TEST');

      var words = serviceA.greeting();

      expect(words).toBe(I say: TEST');
    });
  });

  describe('service B'. function(){
    var serviceB;

    inject(function(_serviceB_){
      serviceB = _serviceB_;
    });

    it('should work', function(){
      var words = serviceB.greeting();
      expect(words).toBe('hello');
    });
  });
});