使用Vitest作为测试运行器时NestJS Testing Module依赖注入失败
NestJS Testing Module与Vitest配合时依赖注入失败问题
问题重现
使用NestJS Testing Module配合Vitest执行测试时,服务无法正确注入,调用方法出现Cannot read properties of undefined (reading 'foo')错误。手动实例化服务的测试可正常运行,但通过Testing Module注入的测试报错。
服务代码
RandomService
import { InjectedOneService } from './injected-one.service'; import { InjectedTwoService } from './intjected-two.service'; export class RandomService { constructor( private readonly injectedOneService: InjectedOneService, private readonly injectedTwoService: InjectedTwoService, ) { } getStr() { return `${this.injectedOneService.foo()} ${this.injectedTwoService.bar()}`; } }
InjectedOneService
import { Injectable } from '@nestjs/common'; @Injectable() export class InjectedOneService { foo() { return 'foo'; } }
InjectedTwoService
import { Injectable } from '@nestjs/common'; @Injectable() export class InjectedTwoService { constructor() { } bar() { return 'bar'; } }
测试代码
import { Test, TestingModule } from '@nestjs/testing'; import { RandomService } from './service'; import { InjectedOneService } from './injected-one.service'; import { InjectedTwoService } from './intjected-two.service'; import { describe, it, expect, vi } from 'vitest'; describe('Service', () => { it('should work without testing module', () => { const injectedOneMockService = new InjectedOneService(); const injectedTwoMockService = new InjectedTwoService(); const result = new RandomService( injectedOneMockService, injectedTwoMockService, ); injectedOneMockService.foo = vi.fn().mockImplementation(() => 'mock foo'); expect(result).toBeDefined(); expect(result.getStr()).toBe('mock foo bar'); }); it('should work with testing module', async () => { const module: TestingModule = await Test.createTestingModule({ providers: [RandomService, InjectedOneService, InjectedTwoService], }).compile(); const injectedOneMockService = module.get<InjectedOneService>(InjectedOneService); const injectedTwoMockService = module.get<InjectedTwoService>(InjectedTwoService); const result = module.get<RandomService>(RandomService); injectedOneMockService.foo = vi.fn().mockImplementation(() => 'mock foo'); injectedTwoMockService.bar = vi.fn().mockImplementation(() => 'mock bar'); expect(result).toBeDefined(); expect(result.getStr()).toBe('mock foo mock bar'); }); });
报错信息
TypeError: Cannot read properties of undefined (reading 'foo') ❯ RandomService.getStr src/vitest-test/service.ts:10:39 8| ) { } 9| getStr() { 10| return `${this.injectedOneService.foo()} ${this.injectedTwoService.bar()}`; | ^ 11| } 12| }
Vitest配置文件
import swc from 'unplugin-swc'; import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { globals: true, root: './', }, plugins: [ swc.vite({ module: { type: 'es6' }, }), ], });
问题原因与解决方法
1. RandomService缺少@Injectable()装饰器
NestJS的依赖注入系统需要通过@Injectable()装饰器标记可注入的服务。你的RandomService未添加该装饰器,导致Testing Module无法识别并处理它的依赖注入逻辑,最终实例化时内部依赖为undefined。
修复代码:
import { Injectable } from '@nestjs/common'; // 导入装饰器 import { InjectedOneService } from './injected-one.service'; import { InjectedTwoService } from './injected-two.service'; @Injectable() // 添加装饰器 export class RandomService { constructor( private readonly injectedOneService: InjectedOneService, private readonly injectedTwoService: InjectedTwoService, ) { } getStr() { return `${this.injectedOneService.foo()} ${this.injectedTwoService.bar()}`; } }
2. 导入路径拼写错误
检查RandomService和测试文件中对InjectedTwoService的导入路径:./intjected-two.service存在拼写错误(少了字母j),正确路径应为./injected-two.service。路径错误会导致实际注入的依赖为undefined,也是报错的潜在原因。
修复导入路径:
// RandomService中 import { InjectedTwoService } from './injected-two.service'; // 测试文件中 import { InjectedTwoService } from './injected-two.service';
验证修复
完成上述修改后重新运行测试,Testing Module即可正确注入依赖,测试应当正常通过。
内容的提问来源于stack exchange,提问作者Steeve
相关产品推荐
相关产品推荐

