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

Nest.js测试模块无法覆盖注入到其他Provider的依赖,获取到undefined

问题原因
    1. 依赖类缺少@Injectable()装饰器:Nest的依赖注入系统要求被注入的Provider必须被@Injectable()修饰,才能收集到依赖元数据,否则DI容器无法识别要注入的实例,导致构造函数拿到undefined。
    1. 纯JS项目缺少显式@Inject声明:如果是JavaScript编写的Nest应用,没有TypeScript的装饰器元数据自动生成能力,必须在构造函数的注入参数前手动添加@Inject(AppInnerService)指定注入token,否则无法匹配到对应的Provider。
    1. 导入错误:如果测试代码中导入AppInnerService时用了TypeScript的仅类型导入(import type)或者路径写错,会导致运行时AppInnerService变量为undefined,overrideProvider传入的token无效,无法完成替换注入。
    1. 特殊作用域冲突:如果AppInnerService设置了REQUEST/TRANSIENT等特殊作用域,默认测试上下文没有对应作用域实例,也会导致注入失败。
修复方案

前置修复

  1. 给AppInnerService添加@Injectable()装饰器:
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppInnerService {
  send(payload: any) {
    // 原有业务逻辑
  }
}
  1. (仅JS项目适用)在AppService构造函数中添加@Inject显式声明注入token:
import { Injectable, Inject } from '@nestjs/common';

@Injectable()
export class AppService {
  constructor(@Inject(AppInnerService) private readonly appInnerService) {}

  publish(payload) {
    this.appInnerService.send(payload);
  }
}
  1. 检查测试代码中AppInnerService的导入语句,确保是普通导入而非仅类型导入,路径和业务代码中的导入路径完全一致。

测试代码优化

你原有测试的overrideProvider逻辑本身是正确的,调整后代码如下即可正常运行,无需手动实例化AppService:

import { Test } from '@nestjs/testing';
import { AppService } from './app.service';
import { AppInnerService } from './app-inner.service'; // 确认导入路径正确

describe('App service', () => {
  let appService: AppService;
  const mockAppInnerService = {
    send: jest.fn(),
  };

  // 建议用beforeEach代替beforeAll,避免单测之间mock状态互相污染
  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      providers: [AppService], // 不需要再声明AppInnerService,已经通过overrideProvider注册了模拟实例
    })
      .overrideProvider(AppInnerService)
      .useValue(mockAppInnerService)
      .compile();

    appService = moduleRef.get<AppService>(AppService);
    // 每次测试前清空mock调用记录
    mockAppInnerService.send.mockClear();
  });

  it('should invoke send method of AppInnerService when publish is called', () => {
    const testPayload = {};
    appService.publish(testPayload);
    expect(mockAppInnerService.send).toHaveBeenCalledWith(testPayload);
  });
});

如果你的AppInnerService是特殊作用域的Provider,直接用上述overrideProvider传入固定模拟实例的方式即可绕过作用域限制,无需额外配置。

内容的提问来源于stack exchange,提问作者Furman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 05:54:04