如何在 Prisma 中对事务包装函数进行单元测试?

Mat*_*our 7 unit-testing transactions jestjs nestjs prisma

我对 Prisma 和 NestJS 很陌生。我有以下事务包装函数,我想通过模拟内部函数来对其进行单元测试reserveSingleBook

这是我的代码(它在 for 循环中执行一些操作,我希望所有这些操作在提交事务之前都成功)。

async reserveBooks(reserveBooksDto: ReserveBoksDto): Promise<SuccessfulReservationResponse> {
    return await this.prisma.$transaction(async (prisma) => {
    
        const reservedBooksResponse = new SuccessfulReservationResponse();
    
        for (const reservation of reserveBooksDto.reservations){
    
          const bookBucket = await this.reserveSingleBook(
            prisma,
            reserveBooksDto.libraryId,
            reservation,
          );
    
          const successfulReservation = new SuccessfulReservation();
          successfulReservation.book_bucket_id = bookBucket.id;
          successfulReservation.units_reserved = reservation.units;
    
          reservedBookssResponse.successful_reservations.push(successfulReservation);    
        }
    
        return reservedBooksResponse
    })
}
Run Code Online (Sandbox Code Playgroud)

这就是我目前对其进行单元测试的方式:

it('should throw an exception when at least a parent book does not exist', async () => {
    // Arrange
    const nonExistingParentBookId = 'non-existing-parentbook-id';
    const existingParentBookId = 'existing-parent-book-id'; 
    const mock = jest.spyOn(service, 'reserveSingleBook');
    mock
    .mockResolvedValueOnce(
      {
        parentBookId: existingParentBookId,
        reserved: 10,
        used: 0,
      } as BookBucket
    )
    .mockRejectedValueOnce(new NotFoundException())
    const reserveBooksDto = new ReserveBooksDto();
    reserveBooksDto.library_id= 'abcde';
    const firstReservation = new Reservation();
    firstReservation.book_id= nonExistingParentBookId;
    firstReservation.units = 10;
    const secondReservation = new Reservation();
    secondReservation.book_id= existingParentBookId;
    secondReservation.units = 10;
    reserveBooksDto.reservations = [firstReservation, secondReservation];

    // Act / Assert
    await expect(service.reserveBooks(
      reserveBooksDto
    )).rejects.toThrowError(NotFoundException);
    expect(mock).toBeCalledTimes(2);

    mock.mockRestore();
});
Run Code Online (Sandbox Code Playgroud)

如果我删除该事务,单元测试将完美工作,因为我的第二个模拟调用返回 NotFoundException,然后将其传递给 ReserveBooks。

但是,当我完成事务时(如果出现任何问题,则不希望提交任何内容),我会在函数调用中得到“未定义”解析,而不是抛出异常。

有谁知道我可能做错了什么?

提前致谢!!

pak*_*ut2 2

您必须监视该$transaction函数并模拟其实现,以便它使用模拟的 prisma 实例作为回调参数。

我不确定你是如何在这里嘲笑 prisma 的,但是这样的东西应该可以解决问题:

jest.spyOn(prisma, '$transaction').mockImplementation((callback) => callback(prismaMock))
Run Code Online (Sandbox Code Playgroud)

哪里prismaMock可能看起来像:

export const prismaMock = {
  entity: { findUnique: jest.fn() }
}
Run Code Online (Sandbox Code Playgroud)

这样prismaMock,您实际上可以避免在每个测试中添加间谍:

export const prismaMock = {
  entity: { findUnique: jest.fn() },
  $transaction: jest.fn().mockImplementation((callback) => callback(prismaMock))
}
Run Code Online (Sandbox Code Playgroud)

希望有帮助。事实上,这种方法可以应用于模拟任何带有回调的函数