I'm trying to prepare some easy parking service api and i'm stuck at testing.
i have ParkingService like:
@Service
@RequiredArgsConstructor
public class ParkingService {
private final CarsAndParkingsRepository carsAndParkingsRepository;
private final ParkingsRepository parkingsRepository;
and simple custom method in repositories
public boolean checkFreeSlots(String idParking) {
return carsAndParkingsRepository.findAmountOfTakenSlotsOnParking(idParking)
< parkingsRepository.findByIdParking(idParking).getNumberOfParkingSlots();
}
and test:
@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);
}
but the problem is i'm getting NullPointerException at line:
when(parkingsRepository.findByIdParking("5").getNumberOfParkingSlots()).thenReturn(10);
Previous mocked method when(carsAndParkingsRepository.findAmountOfTakenSlotsOnParking("5")).thenReturn(5) works correctly, its return 5 but in next line other repository throws exception. Is there any other way to test it or i'm doing something wrong? Ofc, i have mocked repositories :)
The problem is in line:
when(parkingsRepository.findByIdParking("5").getNumberOfParkingSlots()).thenReturn(10);
The argument to when
needs to get evaluated before the call:
parkingsRepository.findByIdParking("5")
is called and return null
null.getNumberOfParkingSlots()
is called and throws NPEYou have following options:
Use a POJO for the Parking
var parking5 = new Parking(
5, //id
10, //number of slots
// ... other arguments
);
when(parkingsRepository.findByIdParking("5")).thenReturn(parking5);
This is the preferred option, but if your object is difficult to construct (it should not be the case for hibernate entity), you can use a mock
Use an mock of the Parking
var parking5 = mock(Parking.class);
when(parkingsRepository.findByIdParking("5")).thenReturn(parking5);
when(parking5.getNumberOfParkingSlots()).thenReturn(10);
Note that you can use chained calls in this approach, but this requires that you stub the methods in order.
var parking5 = mock(Parking.class);
when(parkingsRepository.findByIdParking("5")).thenReturn(parking5);
when(parkingsRepository.findByIdParking("5").getNumberOfParkingSlots()).thenReturn(10);
In my opinion, first flavour is easier to use, and lets you to reorder stubbings.