You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 06:48:04