如何Mock TypeORM @Transaction装饰器注入的EntityManager并使其生效
问题根因
@Transaction() 装饰器的执行逻辑优先级高于手动传参:它会在目标函数执行前主动尝试获取数据库连接、开启事务,完全忽略你手动传入的被 @TransactionManager() 标记的参数,所以单元测试未初始化数据库连接时就会直接抛出 ConnectionNotFound 错误。
可行解决方案
方案1:业务逻辑抽离(最推荐,无侵入生产代码)
把实际业务逻辑从带事务装饰器的入口函数中抽离,单元测试直接测试无装饰器的业务逻辑函数即可:
// 原入口函数,仅负责事务包裹,生产环境调用走这个 @Transaction() public myFunction( myParam: string, @TransactionManager() entityManager?: EntityManager ){ return this.myFunctionCore(myParam, entityManager!); } // 抽离的纯业务逻辑,无任何装饰器,单元测试直接调用这个传mock即可 public async myFunctionCore(myParam: string, entityManager: EntityManager) { // 原函数内所有业务操作迁移到这里 }
方案2:替换官方不推荐的装饰器事务写法
TypeORM 0.3.x 以上版本已经不推荐使用 @Transaction 装饰器实现事务,更推荐手动控制事务边界的写法,天然兼容自定义传入EntityManager:
import { DataSource } from 'typeorm'; // 构造函数注入DataSource constructor(private dataSource: DataSource) {} public async myFunction(myParam: string, entityManager?: EntityManager) { // 有传入的manager直接用,走单元测试分支 if (entityManager) { return this.runBusinessLogic(myParam, entityManager); } // 生产环境自动创建事务 return this.dataSource.transaction(async (txManager) => { return this.runBusinessLogic(myParam, txManager); }); } private async runBusinessLogic(myParam: string, manager: EntityManager) { // 业务逻辑 }
方案3:临时注册mock连接(不推荐,侵入测试逻辑)
如果不想修改业务代码,可以在单元测试初始化阶段给TypeORM的ConnectionManager注册一个mock连接,让装饰器逻辑直接拿到你构造的mock实例,不过这种写法和TypeORM内部实现强绑定,版本升级容易失效。
内容的提问来源于stack exchange,提问作者user3236794
相关产品推荐
相关产品推荐

