Тестирование. Невозможно разрешить все параметры для (ClassName)
Контекст
Я создал класс ApiService
, чтобы иметь возможность обрабатывать наши пользовательские запросы API, используя собственный собственный сериализатор + другие функции.
ApiService
подпись конструктора:
constructor(metaManager: MetaManager, connector: ApiConnectorService, eventDispatcher: EventDispatcher);
-
MetaManager
- это инъекционная служба, которая обрабатывает метаданные api.
-
ApiConnectorService
- это сервис, который обертывает Http
, чтобы добавить наши пользовательские заголовки и систему подписи.
-
EventDispatcher
- это в основном диспетчерская система Symfony, в typescript.
Проблема
Когда я тестирую ApiService
, я инициализирую в beforeEach
:
beforeEach(async(() => {
TestBed.configureTestingModule({
imports : [
HttpModule
],
providers: [
ApiConnectorService,
ApiService,
MetaManager,
EventDispatcher,
OFF_LOGGER_PROVIDERS
]
});
}));
и он отлично работает.
Затем я добавляю свой второй spec файл, который для ApiConnectorService
, с этим beforeEach
:
beforeEach(async(() => {
TestBed.configureTestingModule({
imports : [HttpModule],
providers: [
ApiConnectorService,
OFF_LOGGER_PROVIDERS,
AuthenticationManager,
EventDispatcher
]
});
}));
И все тесты терпят неудачу с этой ошибкой:
Ошибка: не удается разрешить все параметры для ApiService: (MetaManager,?, EventDispatcher).
- Если я удалю
api-connector-service.spec.ts
(ApiConnectorService
spec файл) из моих загруженных тестов, тесты ApiService
будут успешными.
- Если я удаляю
api-service.spec.ts
(ApiService
spec файл) из моих загруженных тестов, тесты ApiConnectorService
будут успешными.
Почему у меня есть эта ошибка? Кажется, что контекст между моими двумя файлами конфликтует, и я не знаю, почему и как это исправить.
Ответы
Ответ 1
Это потому, что служба Http
не может быть разрешена из HttpModule
в тестовой среде. Это зависит от браузера платформы. Вы даже не должны пытаться делать XHR-вызовы во время тестов.
По этой причине Angular предоставляет MockBackend
для службы Http
. Мы используем этот макетный сервер для подписки на соединения в наших тестах, и мы можем издеваться над ответом при каждом соединении.
Вот краткий полный пример, который вы можете отработать
import { Injectable } from '@angular/core';
import { async, inject, TestBed } from '@angular/core/testing';
import { MockBackend, MockConnection } from '@angular/http/testing';
import {
Http, HttpModule, XHRBackend, ResponseOptions,
Response, BaseRequestOptions
} from '@angular/http';
@Injectable()
class SomeService {
constructor(private _http: Http) {}
getSomething(url) {
return this._http.get(url).map(res => res.text());
}
}
describe('service: SomeService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
{
provide: Http, useFactory: (backend, options) => {
return new Http(backend, options);
},
deps: [MockBackend, BaseRequestOptions]
},
MockBackend,
BaseRequestOptions,
SomeService
]
});
});
it('should get value',
async(inject([SomeService, MockBackend],
(service: SomeService, backend: MockBackend) => {
backend.connections.subscribe((conn: MockConnection) => {
const options: ResponseOptions = new ResponseOptions({body: 'hello'});
conn.mockRespond(new Response(options));
});
service.getSomething('http://dummy.com').subscribe(res => {
console.log('subcription called');
expect(res).toEqual('hello');
});
})));
});
Ответ 2
Проблема не была решена в выбранном ответе, что на самом деле просто рекомендация для написания тестов, а скорее в комментариях, и вы должны следовать ссылке и искать ее там. Поскольку у меня была другая проблема с той же ошибкой, я добавлю оба решения здесь.
Если у вас есть ствол (index.ts или multi export file), например:
export * from 'my.component' // using my.service via DI
export * from 'my.service'
Тогда вы можете получить ошибку, например EXCEPTION: Can't resolve all parameters for MyComponent: (?)
.
Чтобы исправить это, вам нужно экспортировать службу перед компонентом:
export * from 'my.service'
export * from 'my.component' // using my.service via DI
- Решение моей проблемы:
Такая же ошибка может произойти из-за circular dependency
, которая вызывает импорт службы undefined
. Чтобы проверить, console.log(YourService)
после импорта (в вашем тестовом файле - там, где проблема возникает). Если он undefined, вы можете сделать файл index.ts(barrel), экспортирующий как сервис, так и файл, используя его (компонент/эффект/все, что вы тестируете) - путем импорта службы из индексного файла, где оба экспортируется (делает его полным).
Найдите этот файл и импортируйте требуемую службу непосредственно из файла your.service.ts
вместо индекса.