NestJS单元测试无法解析PinoLogger依赖问题求助
NestJS单元测试中PinoLogger依赖解析失败问题解决
问题背景
在NestJS应用启动阶段,通过实现OnApplicationBootstrap接口的InitDB服务类,借助TypeORM创建数据库表。编写该服务的单元测试时,虽已配置PinoLogger的模拟实现,但Nest仍无法解析该依赖,报错提示无法找到PinoLogger参数。
服务代码(init-db.service.ts)
import {ConfigService} from '@nestjs/config'; import {PinoLogger} from 'nestjs-pino'; import {Injectable, OnApplicationBootstrap} from '@nestjs/common'; @Injectable() export class InitDB implements OnApplicationBootstrap { constructor(private readonly logger: PinoLogger, private readonly configService: ConfigService) {} onApplicationBootstrap() { this.someMethod(); } async someMethod(): Promise<void> { // code to create tables... } }
单元测试代码(init-db.service.spec.ts)
import {ConfigService} from '@nestjs/config'; import {Test, TestingModule} from '@nestjs/testing'; import {InitDB} from './init-db.service'; import {getLoggerToken, PinoLogger} from 'nestjs-pino'; const mockLogger = { // mock logger functions }; describe('InitDB', () => { jest.useFakeTimers(); let configService: ConfigService; let service: InitDB; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ { provide: getLoggerToken(InitDB.name), // 此处token与服务注入不匹配 useValue: mockLogger, }, InitDB, ConfigService, ], }).compile(); service = module.get<InitDB>(InitDB); configService = module.get<ConfigService>(ConfigService); }); afterEach(() => { jest.clearAllMocks(); }); it('should be defined', () => { expect(service).toBeDefined(); }); });
错误信息
Nest can't resolve dependencies of the BootstrapService (?, ConfigService). Please make sure that the argument PinoLogger at index [0] is available in the RootTestModule context. Potential solutions: - If PinoLogger is a provider, is it part of the current RootTestModule? - If PinoLogger is exported from a separate @Module, is that module imported within RootTestModule? @Module({ imports: [ /* the Module containing PinoLogger */ ] })
解决方案
问题根源是依赖注入的Token不匹配:服务中直接注入PinoLogger类,而测试中使用了nestjs-pino的命名logger Token(getLoggerToken(InitDB.name)),两者无法对应。提供两种解决方式:
方式一:修改服务的注入方式(推荐,符合nestjs-pino最佳实践)
在服务中使用@Inject装饰器指定命名logger的Token,与测试中的配置对齐:
import {ConfigService} from '@nestjs/config'; import {PinoLogger, getLoggerToken} from 'nestjs-pino'; import {Injectable, OnApplicationBootstrap, Inject} from '@nestjs/common'; @Injectable() export class InitDB implements OnApplicationBootstrap { constructor( @Inject(getLoggerToken(InitDB.name)) private readonly logger: PinoLogger, private readonly configService: ConfigService ) {} onApplicationBootstrap() { this.someMethod(); } async someMethod(): Promise<void> { // code to create tables... } }
方式二:修改测试中的Token配置
若不想改动服务代码,直接将测试中的provide改为PinoLogger类,匹配服务的注入方式:
// 测试模块providers配置修改为: providers: [ { provide: PinoLogger, useValue: mockLogger, }, InitDB, ConfigService, ],
原理说明
- 当直接在构造函数中注入
PinoLogger时,Nest会以PinoLogger类作为Token查找依赖; getLoggerToken(...)是nestjs-pino提供的工具函数,用于生成命名logger的唯一Token,仅当服务中通过@Inject(getLoggerToken(...))或PinoLogger.inject(...)装饰器注入时,才会匹配该Token。
内容的提问来源于stack exchange,提问作者s.k
相关产品推荐
相关产品推荐

