javaunit-testingtestingjunitmockito

Mockito ArgumentCaptor needs stubbing even if I use verify?


I am trying to write a Unit Test for the following service method:

public CommandDTO update(UUID uuid, QuantityRequest request) {
        Quantity quantity = quantityRepository.findByUuid(uuid)
                        .orElseThrow(() -> new EntityNotFoundException(QUANTITY));
        Quantity updated = saveQuantity(quantity, request);
        return CommandDTO.builder().uuid(updated.getUuid()).build();
}

private Quantity saveQuantity(Quantity quantity, QuantityRequest request) {
        //map fields (code omitted for brevity)
        return quantityRepository.save(quantity);
}

I use ArgumentCaptor so that I catch the quantity parameter in the private method that my service method calls: quantityRepository.save(quantity).

@Test
public void test() {
    Quantity quantity = new Quantity();

    QuantityRequest request = new QuantityRequest();
    request.setQuantity(100);

    when(quantityRepository.findByUuid(uuid)).thenReturn(Optional.of(quantity));

    // It seems to be meaningless this stubbing. because I already stb it in verify method below
    when(quantityRepository.save(any())).thenReturn(quantity);

    quantityService.update(uuid, request);

    verify(quantityRepository).save(quantityCaptor.capture());
    Quantity captured = quantityCaptor.getValue();

    // assertions...
}

The test is working, but if I remove when(quantityRepository.save(any())).thenReturn(quantity); line, it throws "null pointer exception error" because in this case updated parameter in the update method is null. So, do I have to use the mentioned stubbing in the when() method? I think I do not need it because the verify already performs that task via verify(quantityRepository).save(quantityCaptor.capture()). Is that true?


Solution

  • The problem lies in the following lines:

      Quantity updated = saveQuantity(quantity, request);
      return CommandDTO.builder().uuid(updated.getUuid()).build();
    

    Which is essentially the same as:

     Quantity updated = quantityRepository.save(quantity)
     return CommandDTO.builder().uuid(updated.getUuid()).build();
    

    The stubbing is necessary, because you're expecting the save method to return something, when you call updated.getUuid(). Without the stub, updated is null and your call results in a NullPointerException.