Unit testing Angularjs-如何正确地用模拟替换服务依赖关系

Unit testing Angularjs-如何正确地用模拟替换服务依赖关系,unit-testing,angularjs,karma-runner,Unit Testing,Angularjs,Karma Runner,我正在使用yeoman generator创建的应用程序,并在karma中进行测试 我的每个服务都有可重用的模拟对象。 如何正确地用mock替换特定的服务依赖性,这样我就可以使用jasmine监视方法了 到目前为止,我做了如下工作: 我的服务: angular.module('ql') .service('loginService', ['$http','API','authService', function ($http, API, authService) { return {

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

我的每个服务都有可重用的模拟对象。 如何正确地用mock替换特定的服务依赖性,这样我就可以使用jasmine监视方法了

到目前为止,我做了如下工作:

我的服务:

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,并将其作为一个mock提供,这样它将始终覆盖我的默认实现,但我不想这样做。

我想我只需要使用angular service decorator模拟或完全替换您的服务进行测试

我从未在服务中对服务进行过单元测试,但我们的身份验证/登录功能很快就会出现

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

我想这就是我的方法:(在家长描述中)


我知道这是晚了,但也许它会帮助谁发生在这个职位上的人

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

例如,假设我们正在测试一个服务,该服务利用该服务获取有关当前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'
});

这是解决$injector.get()问题的方法
// 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'
});