Ошибка получения неизвестного поставщика при вводе службы в Angular unit test
Я новичок в Angular и просмотрел все похожие вопросы о переполнении стека, но ни один из них не помог мне. Я считаю, что все правильно настроено, но при попытке ввести службу в unit test я все равно получаю ошибку "Неизвестный поставщик". Я изложил свой код ниже - надеюсь, кто-то может заметить очевидную ошибку!
Я определяю свои модули в отдельном файле .js следующим образом:
angular.module('dashboard.services', []);
angular.module('dashboard.controllers', []);
Здесь я определяю службу под названием EventingService (с логикой, удаленной для краткости):
angular.module('dashboard.services').factory('EventingService', [function () {
//Service logic here
}]);
Вот мой контроллер, который использует EventingService (все это отлично работает во время выполнения):
angular.module('dashboard.controllers')
.controller('Browse', ['$scope', 'EventingService', function ($scope, eventing) {
//Controller logic here
}]);
Вот мой unit test - это строка, в которой я пытаюсь внедрить EventingService, которая вызывает ошибку при запуске unit test:
describe('Browse Controller Tests.', function () {
beforeEach(function () {
module('dashboard.services');
module('dashboard.controllers');
});
var controller, scope, eventingService;
beforeEach(inject(function ($controller, $rootScope, EventingService) {
scope = $rootScope.$new();
eventingService = EventingService
controller = $controller('Browse', {
$scope: scope,
eventing: eventingService
});
}));
it('Expect True to be True', function () {
expect(true).toBe(true);
});
});
Когда я запускаю тест, я получаю эту ошибку:
Ошибка: Неизвестный поставщик: EventingServiceProvider < - EventingService
Я убедился, что в моем файле jasmine specrunner.html есть все необходимые исходные файлы (это проект Asp.Net MVC):
<!-- Include source files here... -->
@Scripts.Render("~/bundles/jquery")
<script type="text/javascript" src="@Url.Content("~/Scripts/angular.js")"></script>
<script type="text/javascript" src="@Url.Content("~/Scripts/angular-mocks.js")"></script>
<script type="text/javascript" src="@Url.Content("~/App/scripts/app.js")"></script> <!-- Angular modules defined in here -->
<script type="text/javascript" src="@Url.Content("~/App/scripts/services/eventing.js")"></script> <!-- My Eventing service defined here -->
<script type="text/javascript" src="@Url.Content("~/App/scripts/controllers/browse.js")"></script> <!-- My Browse controller defined here -->
<!-- Include spec files here... -->
<script type="text/javascript" src="@Url.Content("~/App/tests/browse.js")"></script> <!-- The actual unit test here -->
Я просто не могу понять, почему Angular бросает эту ошибку с жалобами на мой EventingService. Мой контроллер отлично работает во время выполнения - это просто, когда я пытаюсь проверить его, что я получаю сообщение об ошибке, поэтому мне любопытно, что я что-то придумал с насмешкой/инъекцией.
Помощь по тестированию Angular - это мусор, поэтому я сейчас в тупике - любая помощь или предложения, которые кто-либо может дать, будут очень оценены. Спасибо.
Ответы
Ответ 1
Я просто столкнулся с этим и решил его, переключившись на получение сервиса с помощью форварда $явно:
var EventingService, $rootScope;
beforeEach(inject(function($injector) {
EventingService = $injector.get('EventingService');
$rootScope = $injector.get('$rootScope');
}));
Хотел бы я рассказать вам, почему это работает и почему простой
beforeEach(inject(function(EventingService) { .... }));
нет, но у меня нет времени, чтобы исследовать внутренности. Всегда лучше использовать один стиль кодирования и придерживаться его.
Этот стиль лучше в том, что имя переменной, которое вы используете в своих тестах, является правильным именем службы. Но это немного многословно.
Существует еще одна волшебная функция angular, которая использует имена странных переменных, такие как $rootScope, но мне не нравится хакерский вид этого.
Обратите внимание, что большую часть времени люди получают эту ошибку, потому что они не включают модули:
beforeEach(module('capsuling'));
beforeEach(module('capsuling.capsules.services'));
Ответ 2
Если ваши контроллеры (определенные в модуле dashboard.controllers
) зависят от некоторых служб, которые заключены в другой модуль (dashboard.services
), вам нужно ссылаться на модули зависимостей в вашей сигнатуре модуля:
angular.module('dashboard.services', []);
angular.module('dashboard.controllers', ['dashboard.services']);
Ответ 3
Пока этот вопрос довольно старый, я потерял значительное время, решая проблему, подобную этой, т.е.:
Error: Unknown provider: SomeServiceProvider <- SomeService
Следовательно, я оставляю здесь еще одну возможную причину этой проблемы. Надеюсь, это кому-то помогло.
В моем случае у меня в моем проекте были два модуля с точно таким же именем, но с разными зависимостями, создаваемыми, то есть два разных файла .js с:
angular.module('moduleName', [dependencies]))
Из angular документации:
Передача одного аргумента извлекает существующий angular.Module, тогда как передача нескольких аргументов создает новый angular.Module
Заключение. Оказывается, что то, что вводилось в тест, было модулем с неправильными зависимостями. Удаление второго аргумента из модуля, который был ошибочно создан, решает проблему.
Ответ 4
Вы пробовали определить дополнительный модуль, который зависит от ваших других агрегированных модулей следующим образом:
angular.module( 'dashboard', [ 'dashboard.services', 'dashboard.controllers' ] )
Итак, вы можете в beforeEach указать один модуль, который имеет оба подмодуля, определенные в нем так:
describe('Browse Controller Tests.', function () {
beforeEach(function () {
module('dashboard');
});
var controller, scope, eventingService;
beforeEach(inject(function ($controller, $rootScope, EventingService) {
scope = $rootScope.$new();
eventingService = EventingService
controller = $controller('Browse', {
$scope: scope,
eventing: eventingService
});
}));
it('Expect True to be True', function () {
expect(true).toBe(true);
});
});