如何在Nest.js与Jest单元测试中Stub Entity Manager解决连接未找到错误
TypeORM 单元测试Stub EntityManager解决方案
报错原因
你遇到的连接未找到报错,本质是Stub getManager 时没有完整模拟其返回结构,或是Stub时机不正确,导致代码执行时仍然调用了TypeORM原生的getManager逻辑,尝试建立真实数据库连接。
方案1:全局Stub getManager 方法(无需修改现有业务代码)
以下以Jest测试框架为例,其他框架(如Mocha+Sinon)逻辑一致:
// 首先全局mock typeorm的getManager导出 jest.mock('typeorm', () => ({ ...jest.requireActual('typeorm'), getManager: jest.fn() })) it('createStore 方法应正常创建服务实体', async () => { // 1. 构造测试入参和预期返回值 const mockDto = { serviceName: '测试服务' } as ServiceCreateDto const mockEntity = { id: 1001, ...mockDto } as ServiceEntity // 2. 模拟事务实例,实现用到的create、save方法 const mockTransaction = { create: jest.fn().mockReturnValue(mockEntity), save: jest.fn().mockResolvedValue(mockEntity) } // 3. 模拟EntityManager实例,实现用到的transaction方法 const mockManager = { transaction: jest.fn().mockImplementation(async (transactionCallback) => { // 执行传入的事务回调,把模拟的事务实例传进去 await transactionCallback(mockTransaction) }) } // 4. 给getManager打桩,返回模拟的EntityManager实例 (getManager as jest.Mock).mockReturnValue(mockManager) // 5. 调用待测方法 const result = await yourServiceInstance.createStore(mockDto) // 6. 断言验证逻辑正确性 expect(getManager).toHaveBeenCalled() expect(mockTransaction.create).toHaveBeenCalledWith(ServiceEntity, mockDto) expect(mockTransaction.save).toHaveBeenCalledWith(mockEntity) expect(result).toEqual(mockEntity) })
方案2:依赖注入重构(长期项目更推荐)
直接在业务代码中调用全局getManager会导致代码耦合度高,测试不够灵活,建议通过依赖注入的方式传入EntityManager实例:
修改后业务代码
import { EntityManager } from 'typeorm' import { InjectEntityManager } from '@nestjs/typeorm' // 如果用Nest框架的话,否则自行实现注入 class YourService { constructor( // 注入EntityManager实例,不要在方法内部调用getManager @InjectEntityManager() private readonly entityManager: EntityManager, private readonly logger: Logger ) {} async createStore(dto: ServiceCreateDto): Promise<ServiceDto> { let entity: ServiceEntity; try { await this.entityManager.transaction(async transaction => { entity = transaction.create(ServiceEntity, dto) await transaction.save(entity); this.logger.log(`created new Service with serviceId: ${entity.id}`); }); return entity; } catch (error) { throw error; } } }
对应测试代码
不需要全局mock TypeORM,直接构造模拟实例传入构造函数即可:
it('createStore 方法应正常创建服务实体', async () => { const mockDto = { serviceName: '测试服务' } as ServiceCreateDto const mockEntity = { id: 1001, ...mockDto } as ServiceEntity const mockTransaction = { create: jest.fn().mockReturnValue(mockEntity), save: jest.fn().mockResolvedValue(mockEntity) } const mockEntityManager = { transaction: jest.fn().mockImplementation(cb => cb(mockTransaction)) } const mockLogger = { log: jest.fn() } // 直接把模拟的EntityManager传入构造函数 const service = new YourService(mockEntityManager as unknown as EntityManager, mockLogger) const result = await service.createStore(mockDto) expect(mockEntityManager.transaction).toHaveBeenCalled() expect(result).toEqual(mockEntity) })
内容的提问来源于stack exchange,提问作者Mehran Rasheed
相关产品推荐
相关产品推荐

