Инъекции зависимых сервисов при модульном тестировании услуг AngularJS
Я тестирую службу A, но служба A зависит от службы B (то есть услуга B вводится в службу A).
Я видел этот вопрос, но мое дело немного другое, потому что, на мой взгляд, имеет смысл высмеять службу B вместо того, чтобы вводить фактический экземпляр службы Б. Я бы издевался над ним со шпионом-жасмином.
Вот пример теста:
describe("Sample Test Suite", function() {
beforeEach(function() {
module('moduleThatContainsServiceA');
inject([
'serviceA', function(service) {
this.service = service;
}
]);
});
it('can create an instance of the service', function() {
expect(this.service).toBeDefined();
});
});
Ошибка, которую я получаю:
Ошибка: Неизвестный поставщик: serviceBProvider
Как я мог сделать что-то подобное?
Ответы
Ответ 1
На самом деле в AngularJS Dependency Injection используется правило "последних побед". Таким образом, вы можете определить свою услугу в своем тесте сразу после включения вашего модуля и зависимостей, а затем, когда служба A, которую вы тестируете, будет запрашивать службу B с помощью DI, AngularJS предоставит издеваемую версию службы B.
Это часто делается путем определения нового модуля, такого как MyAppMocks, размещения там некорректных сервисов/значений, а затем просто добавления этого модуля в зависимость.
Вид (схематично):
beforeEach(function() {
angular.module('MyAppMocks',[]).service('B', ...));
angular.module('Test',['MyApp','MyAppMocks']);
...
Ответ 2
Я делал это в CoffeeScript и нашел дополнительную информацию. (Кроме того, я нашел код на этой странице путаным.) Здесь полный рабочий пример:
describe 'serviceA', ->
mockServiceB = {}
beforeEach module 'myApp' # (or just 'myApp.services')
beforeEach ->
angular.mock.module ($provide) ->
$provide.value 'serviceB', mockServiceB
null
serviceA = null
beforeEach inject ($injector) ->
serviceA = $injector.get 'serviceA'
it 'should work', ->
expect( true ).toBe( true )
#serviceA.doStuff()
Без явного возврата null после $provide.value
я продолжал получать Error: Argument 'fn' is not a function, got Object
. Я нашел ответ в этом в разделе Google Groups.
Ответ 3
Решение Valentyn работало для меня, но есть и другая альтернатива.
beforeEach(function () {
angular.mock.module("moduleThatContainsServiceA", function ($provide) {
$provide.value('B', ...);
});
});
Затем, когда услуга A AngularJS запрашивает услугу B путем впрыскивания зависимостей, ваш макет службы B будет предоставлен вместо службы B из модуляThatContainsServiceA.
Таким образом, вам не нужно создавать дополнительный модуль angular, чтобы высмеять Сервис.
Ответ 4
Я нахожу, что самый простой метод - это просто ввести службу B и издеваться над ней. например Сервисный автомобиль зависит от сервисного двигателя. Теперь нам нужно высмеять Двигатель при тестировании автомобиля:
describe('Testing a car', function() {
var testEngine;
beforeEach(module('plunker'));
beforeEach(inject(function(engine){
testEngine = engine;
}));
it('should drive slow with a slow engine', inject(function(car) {
spyOn(testEngine, 'speed').andReturn('slow');
expect(car.drive()).toEqual('Driving: slow');
}));
});
Ссылка: https://github.com/angular/angular.js/issues/1635
Ответ 5
Это то, что сработало для меня. Ключ определяет реальный модуль для издевательства. Вызов angular.mock.module делает реальный модуль макетным и позволяет подключать вещи.
beforeEach( ->
@weather_service_url = '/weather_service_url'
@weather_provider_url = '/weather_provider_url'
@weather_provider_image = "test.jpeg"
@http_ret = 'http_works'
module = angular.module('mockModule',[])
module.value('weather_service_url', @weather_service_url)
module.value('weather_provider_url', @weather_provider_url)
module.value('weather_provider_image', @weather_provider_image)
module.service('weather_bug_service', services.WeatherBugService)
angular.mock.module('mockModule')
inject( ($httpBackend,weather_bug_service) =>
@$httpBackend = $httpBackend
@$httpBackend.when('GET', @weather_service_url).respond(@http_ret)
@subject = weather_bug_service
)
)