Пытаясь охватить проект модульными тестами с помощью шутки Nest, я столкнулся с проблемой, когда модуль тестирования не может извлекать переменные из конфигурации.
По сути, у меня есть EmailService, я хочу его протестировать, я использую его как провайдера в своем тестовом модуле. Естественно, поскольку EmailService берет ConfigService в своем конструкторе, чтобы вытащить некоторые переменные из конфига (изначально исходящие из env), я также помещаю ConfigService в массив провайдеров… ну, тогда при инициализации модуль тестирования падает Ошибка NestJS Jest: TypeError: невозможно прочитать свойства неопределенного (чтение «региона»)
примечание: переменная региона берется из env в зарегистрированном модуле конфигурации
пример кода моего теста, который выдает
describe('EmailService', () => {
let emailService: EmailService;
let configService: ConfigService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [EmailService, ConfigService],
}).compile();
emailService = module.get<EmailService>(EmailService);
configService = module.get<ConfigService>(ConfigService);
});
it('should be defined', () => {
expect(emailService).toBeDefined();
});
});
Я пришел к выводу, что он выдает ошибку именно потому, что EmailService принимает ConfigService в своем конструкторе следующим образом:
export class EmailService {
private readonly config: IAwsConfig;
private readonly region: IRegion;
constructor(private readonly configService: ConfigService) {
this.config = this.configService.get('aws');
this.region = this.config.region;
}
дополнительная информация: и EmailService, и ConfigService отлично работают в обычном режиме выполнения, они терпят неудачу только во время шутливого тестирования.
похоже, что метод this.configService.get возвращает «undefined» во время тестового прогона, и я не уверен, почему и как это исправить. Есть идеи?
2 часа подряд не мог найти ответ, но потом, через 10 минут после вопроса, вот и ответ.
Похоже, что ConfigService не предоставляет конфиги во время шутливого тестирования, поэтому вы должны предоставить его в модуле тестирования с замененным методом get, что-то вроде этого:
providers: [
EmailService,
{
provide: ConfigService,
useValue: {
get: jest.fn((key: string) => {
return hardcodedConfigFromWithinTheTestFile;
}),
},
},
],
Если вы не хотите импортировать весь ConfigService, а только сами значения конфигурации, вы используете их в тесте следующим образом:)
// my-config.ts
import { registerAs } from '@nestjs/config';
export default registerAs('myConfig', () => ({ propA: 'aa', propB: 123 }));
import { Inject } from '@nestjs/common';
import { ConfigType } from '@nestjs/config';
import myConfig from './my-config.ts';
export class EmailService {
private propA: string;
private propB: number;
constructor(
@Inject(myConfig.KEY) config: ConfigType<typeof myConfig>
) {
this.propA = config.propA;
this.propB = config.propB;
}
}
import { ConfigModule, registerAs } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
describe('Test', () => {
const configValues = { propA: 'aa', proprB: 123 };
const config = registerAs('testConfig', () => configValues);
beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
imports: [ConfigModule.forFeature(config)],
providers: [EmailService],
}).compile();
});
});
Но так многому предстоит научиться... закончится ли это когда-нибудь? Вероятно, нет: D Спасибо за другое решение. Я попробую сделать это в следующий раз, когда мне нужно решить эту проблему :)