I'm using Spock to unit test a service in my app. Recently I encountered a weird behavior I don't really understand.
Here is my unit test:
def setup() {
parkingSessionRepository = Mock(ParkingSessionRepository.class)
parkingSessionMapper = Stub(ParkingSessionMapper.class)
parkingMeterService = new ParkingMeterService(parkingSessionRepository, parkingSessionMapper)
}
def "should start parking session for vehicle that doesn't have an active parking session"() {
given:
String testVehicleId = "AWC1342"
long testParkingRateId = 1
ParkingStartDTO testParkingStartDTO = ParkingStartDTO.builder()
.vehicleId(testVehicleId)
.parkingRateId(testParkingRateId)
.build()
ParkingSession testParkingSession = ParkingSession.builder()
.vehicleId(testVehicleId)
.parkingRate(ParkingRate.REGULAR)
.build()
parkingSessionMapper.fromParkingStartDTO(_) >> testParkingSession
parkingSessionRepository.save(_ as ParkingSession) >> testParkingSession
parkingSessionRepository.findByVehicleIdAndStopTimeIsNull(_ as String) >> Optional.empty()
when:
ParkingMeterResponseDTO parkingMeterResponseDTO = parkingMeterService.startParkingMeter(testParkingStartDTO)
then:
1 * parkingSessionRepository.save(_ as ParkingSession)
parkingMeterResponseDTO.vehicleId == testVehicleId
Assert.assertNotNull(parkingMeterResponseDTO.parkingSessionId)
Assert.assertNotNull(parkingMeterResponseDTO.timestamp)
}
While code for tested service method is:
public ParkingMeterResponseDTO startParkingMeter(final ParkingStartDTO parkingStartDTO) {
String vehicleId = parkingStartDTO.getVehicleId();
if (isParkingSessionAlreadyActive(vehicleId)) {
throw new ParkingSessionAlreadyActiveException();
} else {
ParkingSession parkingSession = parkingSessionMapper.fromParkingStartDTO(parkingStartDTO);
parkingSession.setStartTime(Timestamp.from(Instant.now()));
parkingSession = parkingSessionRepository.save(parkingSession);
return ParkingMeterResponseDTO.builder()
.vehicleId(parkingSession.getVehicleId())
.parkingSessionId(parkingSession.getId())
.timestamp(parkingSession.getStartTime())
.build();
}
}
Now, when I run unit test there is a result of NullPointerException coming from 'when' block (save() method returns null). However, when I remove save() method check from 'then' block - everything works smoothly, no nulls.
What could be a reason for such behaviour? I suspect some mocking issues with Repository, but I'm not sure what exactly happens under the hood and how to resolve the issue so the save() method check in 'then' block works as intended?