Java >> Java Program >  >> Java

Fånga argument med ArgumentCaptor

1. Översikt

I den här handledningen kommer vi att undersöka hur man fångar metodargument på de hånade metoderna med hjälp av Mockito. För detta ändamål kommer vi att använda ArgumentCaptor klass. I slutändan kommer vi att kunna fånga argument och skriva påståenden mot dem.

2. Exempelapplikation

Låt oss först titta på vår exempelapplikation.

Vi kommer att använda PersonService och PersonRepository klasser. Lägg märke till att PersonService inkluderar PersonRepository som ett beroende.

public class PersonRepository {
...

    public void delete(Person person) {
        System.out.println("Deleting");
    }
}


public class PersonService {

    private final PersonRepository personRepository;

    public PersonService(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }
...

    public void delete(Person person) {
        person.setName("deleted");
        personRepository.delete(person);
    }
}

3. ArgumentCaptor Användning

Nu ska vi titta på användningen av ArgumentCaptor vilket gör det möjligt för oss att fånga argument.

För det första måste vi skapa en instans av ArgumentCaptor med en lämplig typparameter . Sedan måste vi anropa ArgumentCaptor.capture() under verifieringsfasen av vårt test:

@InjectMocks
private PersonService personService;

@Mock
private PersonRepository personRepository;

@Captor
private ArgumentCaptor<Person> captor;

@Test
public void shouldCapture() {
    Person person = new Person("test");

    personService.delete(person);

    Mockito.verify(personRepository).delete(captor.capture());

    Person captured = captor.getValue();

    Assertions.assertThat(captured.getName()).isEqualTo("deleted");
}

Här, PersonService .delete() metoden ställer in personens namn som "raderad". För att verifiera att namnet verkligen har uppdaterats som "raderat" fångar vi Personen argument - på PersonRepository.delete() metod. Sedan gör vi våra påståenden.

Det finns några viktiga punkter att notera här. För det första deklarerar vi ArgumentCaptor med Person som typparameter - ArgumentCaptor . För det andra, fångar vi värdet på verifieringsfasen - Mockito.verify() , inte på förväntningsfasen - Mockito.when() . Och slutligen får vi det infångade värdet med getValue() metod.

4. Flera fångar med ArgumentCaptor

Därefter ska vi se hur vi kan fånga flera värden med ArgumentCaptor .

Tidigare fångade vi bara ett värde, eftersom det bara fanns en anrop. Men vi kan också fånga flera värden:

@InjectMocks
private PersonService personService;

@Mock
private PersonRepository personRepository;

@Captor
private ArgumentCaptor<Person> captor;

@Test
public void shouldCaptureMultipleTimes() {
    personService.delete(new Person("test"));
    personService.delete(new Person("test"));

    Mockito.verify(personRepository, Mockito.times(2)).delete(captor.capture());

    List<Person> allValues = captor.getAllValues();

    for (Person captured : allValues) {
        Assertions.assertThat(captured.getName()).isEqualTo("deleted");
    }
}

Här anropar vi delete() metod två gånger så att två värden fångas upp. Sedan får vi de infångade värdena med getValues() metod.

5. ArgumentCaptor Initiering

Låt oss sedan titta på hur vi kan initiera ArgumentCaptor instanser.

5.1. Initierar ArgumentCaptor med @Captor

För det första använder vi @Captor anteckning för att skapa en fångare :

@Captor
private ArgumentCaptor<Person> captor;

Här deklarerar vi en ArgumentCaptor variabel och kommentera den med @Captor .

Nästa, vi måste få Mockito att upptäcka denna kommentar så att den kan skapa en ArgumentCaptor instans . Det finns flera sätt att uppnå detta. För det första kan vi köra testklassen med Mockitos testlöpare - @RunWith(MockitoJUnitRunner.class). För det andra kan vi kalla MockitoAnnotations.initMocks(this) i testmetoden. Slutligen kan vi deklarera en MockitoRule instans i testklassen. Observera att det här är samma sätt att skapa hån med Mockito.

I vårt fall följer vi den första metoden och kör testet med @RunWith(MockitoJUnitRunner.class).

5.2. Initierar ArgumentCaptor med ArgumentCaptor.forClass()

Ett annat sätt att skapa en ArgumentCaptor är via ArgumentCaptor.forClass() metod. I den här lösningen behöver vi ingen anteckning:

@InjectMocks
private PersonService personService;

@Mock
private PersonRepository personRepository;

@Test
public void shouldCaptureManually() {
    ArgumentCaptor<Person> argumentCaptor = ArgumentCaptor.forClass(Person.class);
    Person person = new Person("test");

    personService.delete(person);

    Mockito.verify(personRepository).delete(argumentCaptor.capture());

    Person captured = argumentCaptor.getValue();

    Assertions.assertThat(captured.getName()).isEqualTo("deleted");
}

Här anropar vi ArgumentCaptor.forClass(Person.class) direkt i testmetoden.

6. Sammanfattning

I den här handledningen har vi tittat på hur vi kan fånga metodargument med Mockitos ArgumentCaptor klass.

Som alltid är källkoden tillgänglig på Github.


Java-tagg