You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 13:01:55