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
相关产品推荐
相关产品推荐

