Angularjs - как правильно заменить зависимость службы с макетом

Я использую созданное приложение генератора йома и делаю свои тесты в карме.

У меня есть многократно используемые объекты для каждого моего сервиса. Как правильно заменить определенную зависимость службы от макета, поэтому я мог бы использовать жасмин, чтобы шпионить за методами

До сих пор я сделал следующее:

Мой сервис:

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 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 и предоставить его как макет, так что он всегда будет переопределять мою реализацию по умолчанию, но я не хочу этого делать.

Ответ 1

Я знаю, что это поздно, но, возможно, это поможет кому-то, кто случится на этом посту.

Отключение службы в Жасмине довольно просто с помощью службы Angular $provide. Хитрость заключается в том, чтобы использовать $provision для замены реализации службы перед инъекцией службы.

Например, скажем, мы тестируем службу, которая использует службу $location для получения информации о текущем URL-адресе.

// load the service 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'
});

Ответ 2

Я думаю, что просто использовал бы конструктор сервисов angular, чтобы издеваться или полностью заменить ваш сервис для тестов. Вот пример

Ответ 3

Я никогда не тестировал сервис в сервисе, но пока что не будет, но наши материалы для авторизации/входа в систему скоро появятся.

Поскольку вы тестируете устройство 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')
   });