Home > Mobile >  Correct way to unit test CrudRepository.save()
Correct way to unit test CrudRepository.save()

Time:12-10

I have a service class which queries the CRUDRepository based on id, name and money.

If data exists, it will extract the money, add 100 to it and save the updated object in the repository. If data does not exist, it will create a new object and save it in the repository.

Person.java

@Value
@Builder
public class Person {

    private final UUID id;
    private final String name;
    @With
    private final BigDecimal money;
    
}

Service.Java

private Person updateOrSave(final UUID id, final String name) {

        final Optional<Person> existingPerson = myRepo.findByIdAndName(id, name);

        if (existingPerson.isPresent()) {
             updatedPerson = existingPerson.withMoney(existingPerson.getMoney().add(new BigDecimal(100)));
            return myRepo.save(updatedPerson);
        } else {
            return myRepo.save(Person.builder()
                .id(id)
                .name(name)
                .money(money)
                .build()));
        }
    }


I need to write a unit test for this scenario where data exists. I am able to write the testcase but the issue is myCrudRepository.save() returns null.

So this is how I am testing it.

Test.java

@ExtendWith(MockitoExtension.class)
class PersonTest {

    @Mock
    private MyRepo myRepo;

    @InjectMocks
    private Service service;
    
    
    
    @Test
    void updateExistingMoney() {

        final UUID id = UUID.randomUUID();
        final String name = "TestName";


        final Optional<Person> person = Optional.of(Person.builder()
                .id(id)
                .name(name)
                .money(new BigDecimal(10))
                .build());

        final Person finalPerson = Person.builder()
                .id(id)
                .name(name)
                .money(new BigDecimal(110))
                .build()

        when(myRepo.findByIdAndName(id, name))
            .thenReturn(person);

        service.updateOrSave(id, name);

        verify(myRepo).save(finalPerson);

    }
    

Is this correct way of testing or is it wrong ?

CodePudding user response:

You can use the concept of Argument captors to capture the object, which was passed as an argument to the mocked repo.

@ExtendWith(MockitoExtension.class)
class PersonTest {

    @Mock
    private MyRepo myRepo;

    @InjectMocks
    private Service service;

    @Captor
    private ArgumentCaptor<Person> personCaptor;


    @Test
    void updateExistingMoney() {

        final UUID id = UUID.randomUUID();
        final String name = "TestName";


        final Optional<Person> person = Optional.of(Person.builder()
                .id(id)
                .name(name)
                .money(new BigDecimal(10))
                .build());

        final Person finalPerson = Person.builder()
                .id(id)
                .name(name)
                .money(new BigDecimal(110))
                .build()

        when(myRepo.findByIdAndName(id, name))
                .thenReturn(person);

        service.updateOrSave(id, name);

        verify(myRepo).save(personCaptor.capture());

        final Person actual = personCaptor.getValue();

        // Do checks on expected person vs. the actual one
    }
  • Related