休眠 - 为什么模拟方法抛出 NullPointerException

hibernate - why mocked method throws NullPointerException

我正在尝试准备一些简单的停车服务api,但我还在测试中。

我有这样的停车服务:

@Service
@RequiredArgsConstructor
public class ParkingService {
      private final CarsAndParkingsRepository carsAndParkingsRepository;
      private final ParkingsRepository parkingsRepository;

和存储库中的简单自定义方法

public boolean checkFreeSlots(String idParking) {
    return carsAndParkingsRepository.findAmountOfTakenSlotsOnParking(idParking)
            < parkingsRepository.findByIdParking(idParking).getNumberOfParkingSlots();
}

并测试:

 @Test
public void checkFreeSlotsIfIsCorrect() {
    //given

    //when
    when(carsAndParkingsRepository.findAmountOfTakenSlotsOnParking("5")).thenReturn(5);
    when(parkingsRepository.findByIdParking("5").getNumberOfParkingSlots()).thenReturn(10);
    when(parkingService.checkFreeSlots("5")).thenCallRealMethod();
    boolean result = parkingService.checkFreeSlots("5");

    //then
    assertEquals(true, result);
}

但问题是我在以下行收到 NullPointerException:

when(parkingsRepository.findByIdParking("5").getNumberOfParkingSlots()).thenReturn(10);

Previous mocked 方法 when(carsAndParkingsRepository.findAmountOfTakenSlotsOnParking("5")).thenReturn(5) 工作正常,它的 return 5 但在下一行其他存储库抛出异常。 有没有其他方法可以测试它或者我做错了什么? Ofc,我模拟了存储库 :)

问题所在行:

when(parkingsRepository.findByIdParking("5").getNumberOfParkingSlots()).thenReturn(10);

when 的参数需要在调用前求值:

  • parkingsRepository.findByIdParking("5") 被调用并且 return null
  • null.getNumberOfParkingSlots() 被调用并抛出 NPE

您有以下选择:

使用 POJO 停车

var parking5 = new Parking(
    5, //id
   10, //number of slots
   // ... other arguments
);
when(parkingsRepository.findByIdParking("5")).thenReturn(parking5);

这是首选方案,但如果您的对象难以构建(hibernate 实体不应该如此),您可以使用 mock

使用模拟停车场

var parking5 = mock(Parking.class);
when(parkingsRepository.findByIdParking("5")).thenReturn(parking5);
when(parking5.getNumberOfParkingSlots()).thenReturn(10);

请注意,您可以在此方法中使用链式调用,但这需要您按顺序存根方法。

var parking5 = mock(Parking.class);
when(parkingsRepository.findByIdParking("5")).thenReturn(parking5);
when(parkingsRepository.findByIdParking("5").getNumberOfParkingSlots()).thenReturn(10);

在我看来,first flavor 更容易使用,并且可以让你重新排序 stubbings。