NestJS Jest单元测试中AppLogger依赖注入失败问题排查
NestJS构造函数注入AppLogger依赖失败排查方案
问题现象
- HealthCheckController构造函数中,
HealthCheckService实例注入成功,但AppLogger始终为null - 注释控制器里的
appLogger参数后,控制器能正常初始化,但执行await module.resolve<AppLogger>(AppLogger)会直接失败
相关代码片段
控制器代码
export class HealthCheckController { constructor(@Inject('HealthCheckService') private healthCheckService: HealthCheckService, private appLogger: AppLogger) { } }
测试代码
beforeEach(async () => { module = await Test.createTestingModule({ controllers: [HealthCheckController], providers: [ AppLoggerNope.getProvider(), { provide: 'HealthCheckService', useClass: HealthCheckService }, ], }) .compile(); controller = await module.resolve<HealthCheckController>(HealthCheckController); const logger = await module.resolve<AppLogger>(AppLogger); service = await module.resolve<HealthCheckService>('HealthCheckService'); });
AppLoggerNope代码
export class AppLoggerNope { static getProvider() { return { provide: AppLogger, useValue: {} } } }
问题根源
- AppLogger类未标记为可注入:NestJS的DI容器要求所有需要注入的类必须添加
@Injectable()装饰器,否则容器无法识别这个类型作为注入令牌。即使使用自定义提供者(useValue),如果AppLogger本身没有被标记,容器无法关联对应的实例。 - 测试容器无法匹配令牌:调用
module.resolve<AppLogger>(AppLogger)时,容器找不到对应令牌的提供者,说明AppLogger这个类型没有被正确注册到测试模块的DI系统中。
解决步骤
1. 给AppLogger添加@Injectable()装饰器
import { Injectable } from '@nestjs/common'; @Injectable() export class AppLogger { // 实现日志方法,比如log、error等 }
2. 验证自定义提供者的正确性
确保AppLoggerNope.getProvider()返回的提供者中,provide字段的令牌与控制器中注入的AppLogger类完全一致。只要AppLogger被标记为@Injectable(),当前的provide: AppLogger配置就是有效的。
3. 调整测试代码中的实例获取方式
建议用module.get()替代module.resolve(),前者更适合测试场景下从容器获取实例:
beforeEach(async () => { module = await Test.createTestingModule({ controllers: [HealthCheckController], providers: [ AppLoggerNope.getProvider(), { provide: 'HealthCheckService', useClass: HealthCheckService }, ], }).compile(); controller = module.get<HealthCheckController>(HealthCheckController); const logger = module.get<AppLogger>(AppLogger); service = module.get<HealthCheckService>('HealthCheckService'); });
4. 确认控制器注入语法
如果AppLogger是类类型注入,不需要额外添加@Inject()装饰器,只要类本身是@Injectable()且已在模块中注册,就能正常注入:
constructor( @Inject('HealthCheckService') private healthCheckService: HealthCheckService, private appLogger: AppLogger // 直接使用类类型注入即可 ) {}
内容的提问来源于stack exchange,提问作者Vova Bilyachat
相关产品推荐
相关产品推荐

