13

我正在使用 yeoman 生成器创建的应用程序,并在 karma 中进行测试。

我的每项服务都有可重用的模拟对象。我如何正确地用模拟替换特定的服务依赖关系,这样我就可以使用茉莉花来监视方法

到目前为止,我已经这样做了:

我的服务:

angular.module('ql')
  .service('loginService', ['$http','API','authService', function ($http, API, authService) {
    return {
      //service implementation
    }]);

authService 的模拟:

'use strict';
//lets mock http auth  service, so it would be spied upon.
ql.mock.$authServiceMockProvider = function() {
  this.$get = function() {
    var $service = {
      loginConfirmed: function() { }
    };
    return $service;
  };
};

//and register it.
angular.module('qlMock').provider({
  $authServiceMock: ql.mock.$authServiceMockProvider
});

我的测试:

'use strict';

describe('When i call login method()', function () {

  // load the service's module
  beforeEach(module('ql'));
  beforeEach(angular.mock.module('qlMock'));

  // instantiate service
  var loginService,
  authService,
  $httpBackend;
  beforeEach(function() {
    // replace auth service with a mock.
    // this seems kind of dirty... is there a bettery way? 
    module(function($provide, $injector){
      authService = $injector.get('$authServiceMockProvider').$get();
      $provide.value('authService', authService);
    });

    //actually get the loginService
    /*jshint camelcase: false */
    inject(function(_loginService_, _$httpBackend_) {
      loginService = _loginService_;
      $httpBackend =_$httpBackend_;
    });

    //http auth module method, that should be call only on success scenarios
    spyOn(authService, 'loginConfirmed').andCallThrough();
  });
  it('it should do something', function () {
  //actual test logic
  });
});

我不喜欢的是这条线:

authService = $injector.get('$authServiceMockProvider').$get();

我想简单地以某种方式获取 authServiceMock(无需获取提供程序,并调用 et 方法),然后将其注入 loginService。

我知道我可以简单地调用我的 $authServiceMock authService,并将其作为模拟提供,以便它始终覆盖我的默认实现,但我不想这样做。

4

3 回答 3

15

我知道这已经晚了,但也许它会帮助发生在这篇文章中的人。

使用 Angular 的$provide服务在 Jasmine 中模拟服务非常简单。诀窍是在注入服务之前使用 $provide 换出服务实现。

例如,假设我们正在测试一项服务,该服务利用$location服务来获取有关当前 URL 的信息。

// load the service's module under test
beforeEach(module('myExampleModule'));

// mock out $location with a fake one
beforeEach(module(function ($provide) {

   //create mock impl
     var mockLocation = {
         path: function(){
                 return '/somewhere'
                 }
              }

$provide.value('$location', mockLocation); // use $provide to swap the real $location with our mock
}));

var $location;
// inject dependencies ($location will be our mocked $location)
beforeEach(inject(function (_$location_) {
 $location = _$location_;
}));

it('should return mock url', function(){
      var path = $location.path();
      expect(path).toBe('/somewhere'); //Assert that $location.path() returns '/somewhere'
});
于 2014-07-10T18:25:20.393 回答
0

我从来没有在服务中对服务进行单元测试,反正还没有,但我们的身份验证/登录内容很快就会出现。

当您对 loginService 进行单元测试时,您只对服务与 AuthService 提供的数据交互的方式感兴趣,而不是 AuthService 是否正常工作。这是你在模拟中设置的。

我认为这将是我的方法:(在父描述中)

  var   
     loginService, 
     authService
     AUTH_DATA
  ;

  beforeEach(function() {
     module('ql');
     // I am assuming this is the global app module so both services live here? If not include this module as well
  });


   beforeEach(inject(function (_authService_, _loginService_) {
      authService = _authService_;
      loginService = _loginService_;
      //Now with the spy setup you intercept the calls to the service and you choose what data to return, based on the unit test. Now your LoginService can simply resond to the data it is give from the login service
    }));

  it('it should do something', function () {
     spyOn(authService, 'loginConfirmed').andReturn(AUTH_DATA);
     loginService.confirmLogin(); //Dont know your actual API but a contrived guess
     expect('something to happen in loginservice when AUTH_DATA is returned').toBe('Something else')
   });
于 2014-03-24T06:33:36.497 回答
0

我想我会简单地使用一个角度服务装饰器来模拟或完全替换您的测试服务。这是一个例子

于 2013-11-22T13:49:14.710 回答