NestJS中TestingModule.get()获取的EntityManager未被Mock的原因及解决方法
问题解答
1. 行为差异的原因
这是因为NestJS的TypeORM模块对EntityManager和Repository的注入逻辑存在差异:
- 对于通过
getRepositoryToken(Entity, 'replica')注册的Repository,Nest会直接使用你提供的Mock实例,不会额外自动创建真实对象——因为Repository是绑定到特定实体和连接的具象化依赖,不存在自动实例化的兜底逻辑。 - 对于EntityManager,TypeORM模块内部存在自动实例化逻辑:如果测试模块中存在TypeORM的连接配置(哪怕是隐式的,比如Service所在模块导入了TypeORMModule),Nest会优先从连接池中获取真实的EntityManager实例,直接覆盖你通过
getEntityManagerToken('replica')注册的Mock,这就是你拿到全新未Mock实例的核心原因。
2. 可以通过moduleRef获取正确Mock的EntityManager
完全可以,只要调整测试模块的配置,阻断Nest自动创建真实EntityManager的逻辑即可。
3. 具体实现方案
核心是确保测试模块不引入真实的TypeORM连接配置,并明确覆盖EntityManager的注入逻辑。修正后的代码示例如下:
import { Test, TestingModule } from '@nestjs/testing'; import { getEntityManagerToken, getRepositoryToken } from '@nestjs/typeorm'; import { EntityManager, Inject } from 'typeorm'; const mockEntityManager = () => ({ query: jest.fn(), find: jest.fn(), findOne: jest.fn(), }); // 示例Service结构 class Service { constructor( @Inject(getEntityManagerToken('replica')) private readonly replicaManager: EntityManager, @Inject(getRepositoryToken(Entity, 'replica')) private readonly replicaRepo: any, ) {} } describe('TEST', () => { let sut: Service; let replicaRepositoryStub: any; let replicaManagerStub: any; beforeEach(async () => { // 提前创建Mock实例,便于后续统一引用 const mockManager = mockEntityManager(); const mockRepo = mockEntityManager(); const moduleRef: TestingModule = await Test.createTestingModule({ providers: [ Service, { provide: getEntityManagerToken('replica'), useValue: mockManager, }, { provide: getRepositoryToken(Entity, 'replica'), useValue: mockRepo, }, ], // 关键:不要导入TypeORMModule.forRoot()或forFeature(),避免触发真实连接创建 }).compile(); sut = moduleRef.get<Service>(Service); replicaRepositoryStub = moduleRef.get(getRepositoryToken(Entity, 'replica')); replicaManagerStub = moduleRef.get(getEntityManagerToken('replica')); }); it('test1', async () => { replicaRepositoryStub.findOne.mockResolvedValue('test'); replicaManagerStub.findOne.mockResolvedValue('test'); // 现在可正常执行,不会报错 }); });
如果测试必须导入包含TypeORMModule的业务模块,可通过overrideProvider强制覆盖EntityManager的注入:
const moduleRef: TestingModule = await Test.createTestingModule({ imports: [YourFeatureModule], // 该模块内部导入了TypeORMModule providers: [Service], }) .overrideProvider(getEntityManagerToken('replica')) .useValue(mockManager) .compile();
内容的提问来源于stack exchange,提问作者Austin
相关产品推荐
相关产品推荐

