Краткая сводка /TL;DR:
- Кажется, что процесс поиска контейнера Ember + модуль-преобразователь Ember-CLI не позволяет вручную отменить регистрацию службы, а затем зарегистрировать замену, если исходная услуга может быть разрешена с помощью
resolver
(я хочу сделать метод описанный здесь, но он не работает) - Как я могу издеваться над сервисом Ember-CLI в приемочном тесте без использования хакерского, настраиваемого разрешения? (пример проекта/приемочный тест здесь)
Подробное объяснение + пример
Создайте новую службу, которая вводится в контроллер:
ember generate service logger
услуги/logger.js
export default Ember.Object.extend({
log: function(message){
console.log(message);
}
});
инициализаторы/Регистратор-service.js
export function initialize(container, application) {
application.inject('route', 'loggerService', 'service:logger');
application.inject('controller', 'loggerService', 'service:logger');
}
Доступ к службе осуществляется через его введенное имя loggerService
в обработчике действий на контроллере приложения:
Использовать службу в контроллере
Шаблоны/application.hbs
<button id='do-something-button' {{action 'doSomething'}}>Do Something</button>
Контроллеры/application.hs
export default Ember.Controller.extend({
actions: {
doSomething: function(){
// access the injected service
this.loggerService.log('log something');
}
}
});
Попытка проверить правильность этого поведения
Я создал приемочный тест, который проверяет, что нажатие кнопки вызывает услугу. Цель состоит в том, чтобы издеваться над сервисом и определить, был ли он вызван без фактического запуска реализации сервиса - это позволяет избежать побочных эффектов реального сервиса.
ember generate acceptance-test application
тесты/принятие/приложение-test.js
import Ember from 'ember';
import startApp from '../helpers/start-app';
var application;
var mockLoggerLogCalled;
module('Acceptance: Application', {
setup: function() {
application = startApp();
mockLoggerLogCalled = 0;
var mockLogger = Ember.Object.create({
log: function(m){
mockLoggerLogCalled = mockLoggerLogCalled + 1;
}
});
application.__container__.unregister('service:logger');
application.register('service:logger', mockLogger, {instantiate: false});
},
teardown: function() {
Ember.run(application, 'destroy');
}
});
test('application', function() {
visit('/');
click('#do-something-button');
andThen(function() {
equal(mockLoggerLogCalled, 1, 'log called once');
});
});
Это основано на разговоре Тестирование Ember Apps: Управление зависимостью от mixonic, который рекомендует отменить регистрацию существующей службы, а затем перерегистрировать измененную версию:
application.__container__.unregister('service:logger');
application.register('service:logger', mockLogger, {instantiate: false});
К сожалению, это не работает с Ember-CLI. Преступник эта строка в контейнере Ember:
function resolve(container, normalizedName) {
// ...
var resolved = container.resolver(normalizedName) || container.registry[normalizedName];
// ...
}
который является частью цепочки поиска контейнера. Проблема в том, что контейнер resolve
проверяет resolver
перед проверкой его внутреннего registry
. Команда application.register
регистрирует нашу издеваемую службу с контейнером registry
, но когда resolve
вызывается, контейнер проверяет с помощью resolver
, прежде чем он запросит registry
. Ember-CLI использует пользовательский resolver
для соответствия поисковым запросам модулей, что означает, что он всегда будет разрешать исходный модуль, а не использовать недавно зарегистрированный макет службы. Обходной путь для этого выглядит ужасно и включает в себя модификацию resolver
, чтобы никогда не находить оригинальный сервисный модуль, который позволяет контейнеру использовать зарегистрированную вручную mock-службу.
Измените Resolver, чтобы избежать разрешения на исходный сервис
Использование пользовательского resolver
в тесте позволяет успешно издеваться над сервисом. Это работает, позволяя распознавателю выполнять нормальный поиск, но когда наше имя службы просматривается, измененный распознаватель действует так, как будто у него нет модуля, соответствующего этому имени. Это приводит к тому, что метод resolve
обнаруживает зарегистрированную вручную ложную службу в контейнере.
var MockResolver = Resolver.extend({
resolveOther: function(parsedName) {
if (parsedName.fullName === "service:logger") {
return undefined;
} else {
return this._super(parsedName);
}
}
});
application = startApp({
Resolver: MockResolver
});
Кажется, что это не обязательно и не соответствует предлагаемому сервису, издевающемуся над вышеуказанными слайдами. Есть ли лучший способ издеваться над этим сервисом?
Проект ember-cli, используемый в этом вопросе, можно найти в этом примере проекта на github.