ConfigModel: Использует featureConfigurationClass через DI
Обзор
Тесты проверяют ConfigModel в nestjs-mod: преобразование конфигурации, валидацию данных и контракт ошибок при некорректных параметрах.
Что мы тестируем
- Конфигурация на основе классов: Убеждаемся, что конфигурация может быть предоставлена как инжектируемый класс
- Внедрение зависимостей в конфигурацию: Проверяем, что классы конфигурации могут инжектировать и использовать другие сервисы
- Фабричный паттерн: Тестируем асинхронный фабричный паттерн для конфигурации фич
- Интеграция сервисов: Подтверждаем, что инжектированные сервисы работают корректно внутри классов конфигурации
Ссылка на GitHub
- Файл: utils.spec.ts
- Строки: 619-703
Подготовительный код
Этот тест создает класс конфигурации, который инжектирует вспомогательный сервис:
import { Injectable } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { ConfigModel, ConfigModelProperty } from '../config-model/decorators';
import { InjectableFeatureConfigurationType } from './types';
import { createNestModule, getNestModuleDecorators } from './utils';
@ConfigModel()
class DatabaseFeatureConfig {
@ConfigModelProperty({ default: 'localhost' })
host!: string;
@ConfigModelProperty({ default: 5432 })
port!: number;
@ConfigModelProperty({ default: 'mydb' })
database!: string;
}
// Сервис для внедрения в класс конфигурации
@Injectable()
class ConfigHelper {
getDefaultHost() {
return 'db.example.com';
}
}
const { InjectFeatures } = getNestModuleDecorators({
moduleName: 'DatabaseModule',
});
@Injectable()
class DatabaseService {
constructor(
@InjectFeatures()
private readonly featureConfigs: InjectableFeatureConfigurationType<DatabaseFeatureConfig>[],
) {}
getFeatureConfigs() {
return this.featureConfigs;
}
}
const { DatabaseModule } = createNestModule({
moduleName: 'DatabaseModule',
featureConfigurationModel: DatabaseFeatureConfig,
sharedProviders: [DatabaseService, ConfigHelper],
});
// Класс конфигурации с DI - конструктор может инжектировать зависимости
@Injectable()
class DatabaseConfigClass {
constructor(private readonly configHelper: ConfigHelper) {}
host = this.configHelper.getDefaultHost();
port = 5432;
database = 'production_db';
}
Код теста
it('should use featureConfigurationClass with DI', async () => {
const { AppModule } = createNestModule({
moduleName: 'AppModule',
imports: [
DatabaseModule.forFeatureAsync({
featureModuleName: 'MainDatabase',
featureConfigurationClass: DatabaseConfigClass,
inject: [ConfigHelper],
}),
],
});
const moduleRef: TestingModule = await Test.createTestingModule({
imports: [DatabaseModule.forRoot(), AppModule.forRoot()],
providers: [ConfigHelper],
}).compile();
const databaseService = moduleRef.get(DatabaseService);
const featureConfigs = databaseService.getFeatureConfigs();
expect(featureConfigs).toBeDefined();
expect(featureConfigs.length).toBeGreaterThanOrEqual(1);
const config = featureConfigs[0];
expect(config.featureModuleName).toBe('MainDatabase');
expect(config.featureConfiguration).toMatchObject({
host: 'db.example.com', // От инжектированного ConfigHelper
port: 5432,
database: 'production_db',
});
});
Что делает этот тест
-
Создает сервис ConfigHelper, который предоставляет значения конфигурации по умолчанию
-
Создает DatabaseConfigClass, который:
- Декорирован
@Injectable()для поддержки DI - Инжектирует
ConfigHelperв своем конструкторе - Использует инжектированный хелпер для вычисления значения
host - Устанавливает другие свойства напрямую
- Декорирован
-
Создает DatabaseModule с:
featureConfigurationModel, определяющим структуру конфигурации- Оба
DatabaseServiceиConfigHelperкак общие провайдеры
-
Создает AppModule, который:
- Использует
forFeatureAsyncсfeatureConfigurationClass - Указывает, какие зависимости
inject([ConfigHelper]) - Называет модуль фичи 'MainDatabase'
- Использует
-
Компилирует модуль и получает
DatabaseService -
Проверяет, что:
- Конфигурации фич определены
- Конфигурация создана из кл асса
- Значение
hostпришло от инжектированногоConfigHelper('db.example.com') - Другие значения соответствуют свойствам класса
Ключевые моменты
- Этот тест фиксирует контракт поведения конкретного блока nestjs-mod в условиях данного сценария.
- Проверки в тесте защищают интеграционные границы и предотвращают регрессии при изменении внутренней реализации.