如何正确模拟构造函数含字符串参数的Injectable服务?
如何正确模拟带有自定义注入令牌的NestJS服务?
我有一个简单的可注入服务,代码如下:
@Injectable() export class MyService { constructor(@Inject('Container') container: string) { // ... } }
我尝试对其进行模拟,测试模块代码如下:
const module = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ isGlobal: true, }), ], providers: [ { provide: MyService, useValue: { find: (id: string) => 'test' } }, { provide: 'Container', useValue: 'AnyValue' }, ], }).compile(); await module.init();
但模拟并未生效,该服务仍在发起网络请求。请问该如何正确模拟这个服务?
可能的原因及解决方法
1. 确保使用测试容器中的模拟实例
检查测试代码是否从测试模块中获取MyService实例,而非直接创建真实服务:
// 正确方式:从测试容器获取模拟实例 const myService = module.get<MyService>(MyService); // 测试中使用这个实例调用方法
如果直接通过new MyService(...)创建实例,测试模块的模拟配置完全不会生效,自然会执行真实服务的网络请求逻辑。
2. 显式覆盖提供者避免依赖冲突
如果测试模块导入的其他模块(比如全局ConfigModule)间接引入了真实的MyService,NestJS可能会优先加载真实实例。此时使用overrideProvider强制替换:
const module = await Test.createTestingModule({ imports: [ConfigModule.forRoot({ isGlobal: true })], }) .overrideProvider(MyService) .useValue({ find: (id: string) => 'test', // 补充所有需要模拟的方法,比如发起请求的方法 fetchData: () => Promise.resolve('mock response') }) .compile();
3. 完整模拟服务的所有用到的方法
如果MyService中有多个方法,而你只模拟了find,未被模拟的方法(比如发起网络请求的方法)会执行真实逻辑。需要确保模拟对象覆盖测试中用到的所有方法:
{ provide: MyService, useValue: { find: (id: string) => 'test', // 例如:模拟发起网络请求的方法 sendRequest: () => Promise.resolve({ data: 'mock' }) } }
4. 控制全局模块的影响
全局ConfigModule可能引入未预期的依赖,导致真实服务被加载。可以尝试关闭全局配置,或者限制模块的作用范围:
ConfigModule.forRoot({ isGlobal: false, // 关闭全局模式 // 测试所需的配置项 })
内容的提问来源于stack exchange,提问作者Rodrigo
相关产品推荐
相关产品推荐

