Nest.js测试模块无法覆盖注入到其他Provider的依赖,获取到undefined
问题原因
- 依赖类缺少
@Injectable()装饰器:Nest的依赖注入系统要求被注入的Provider必须被@Injectable()修饰,才能收集到依赖元数据,否则DI容器无法识别要注入的实例,导致构造函数拿到undefined。
- 依赖类缺少
- 纯JS项目缺少显式
@Inject声明:如果是JavaScript编写的Nest应用,没有TypeScript的装饰器元数据自动生成能力,必须在构造函数的注入参数前手动添加@Inject(AppInnerService)指定注入token,否则无法匹配到对应的Provider。
- 纯JS项目缺少显式
- 导入错误:如果测试代码中导入
AppInnerService时用了TypeScript的仅类型导入(import type)或者路径写错,会导致运行时AppInnerService变量为undefined,overrideProvider传入的token无效,无法完成替换注入。
- 导入错误:如果测试代码中导入
- 特殊作用域冲突:如果
AppInnerService设置了REQUEST/TRANSIENT等特殊作用域,默认测试上下文没有对应作用域实例,也会导致注入失败。
- 特殊作用域冲突:如果
修复方案
前置修复
- 给
AppInnerService添加@Injectable()装饰器:
import { Injectable } from '@nestjs/common'; @Injectable() export class AppInnerService { send(payload: any) { // 原有业务逻辑 } }
- (仅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); } }
- 检查测试代码中
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
相关产品推荐
相关产品推荐

