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

NestJS中Prisma事务包裹函数单元测试异常未抛出问题排查

问题排查与解决思路

给你捋几个最可能踩的坑:

1. 事务里没正确生成Promise数组

如果你的reserveBooks用forEach循环调用reserveSingleBook,那完全是无效操作——forEach不处理异步返回值,prisma.$transaction根本拿不到要等待的Promise列表,直接就执行完毕,错误自然抛不出来。

正确姿势是用map生成Promise数组,再通过Promise.all等待全部完成:

// 错误写法
async reserveBooks(bookIds: string[]) {
  await prisma.$transaction(async (tx) => {
    bookIds.forEach(async (id) => {
      await this.reserveSingleBook(tx, id); // forEach的异步操作不会被事务等待
    });
  });
}

// 正确写法
async reserveBooks(bookIds: string[]) {
  await prisma.$transaction(async (tx) => {
    await Promise.all(
      bookIds.map(async (id) => {
        await this.reserveSingleBook(tx, id);
      })
    );
  });
}

2. 函数吞掉了事务的错误

如果reserveBooks里加了try/catch,但catch块没把错误重新抛出来,事务抛出的异常就会被吞掉,函数自然返回undefined:

// 错误写法
async reserveBooks(bookIds: string[]) {
  try {
    await prisma.$transaction(/* ... */);
  } catch (e) {
    // 只打了日志或啥也没做,没重新抛错
    console.log(e);
  }
}

// 正确写法
async reserveBooks(bookIds: string[]) {
  try {
    await prisma.$transaction(/* ... */);
  } catch (e) {
    // 重新抛出错误,让上层能捕获
    throw e;
  }
}

3. Mock的异常类型或抛出方式不对

确保你mock的reserveSingleBook是正确抛出NotFoundException实例,而非字符串或其他错误类型:

// 正确的mock写法
jest.spyOn(bookService, 'reserveSingleBook')
  .mockResolvedValueOnce(/* 成功返回值 */)
  .mockRejectedValueOnce(new NotFoundException('Book not found'));

如果只是抛个字符串,上层可能识别不到预期异常,或者被Prisma事务的错误处理逻辑包裹后,测试里无法正确捕获。

4. 测试里没正确等待异步操作

虽然你说移除事务时测试正常,但还是确认下测试代码是否用了await或rejects断言:

// 正确的测试写法
it('should throw NotFoundException when one book is missing', async () => {
  // ... mock setup

  // 用await + expect.toThrow
  await expect(bookService.reserveBooks(['valid-id', 'invalid-id'])).rejects.toThrow(NotFoundException);
});

内容的提问来源于stack exchange,提问作者Matheus Mansour

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:19:22