web-dev-qa-db-fra.com

Mockito peut-il capturer les arguments d'une méthode appelée plusieurs fois?

J'ai une méthode appelée deux fois et je veux capturer l'argument du second appel de méthode.

Voici ce que j'ai essayé:

ArgumentCaptor<Foo> firstFooCaptor = ArgumentCaptor.forClass(Foo.class);
ArgumentCaptor<Foo> secondFooCaptor = ArgumentCaptor.forClass(Foo.class);
verify(mockBar).doSomething(firstFooCaptor.capture());
verify(mockBar).doSomething(secondFooCaptor.capture());
// then do some assertions on secondFooCaptor.getValue()

Mais je reçois une TooManyActualInvocations Exception, car Mockito pense que doSomething ne devrait être appelé qu'une seule fois.

Comment puis-je vérifier l'argument du second appel de doSomething?

389
Eric Wilson

Je pense que ça devrait être

verify(mockBar, times(2)).doSomething(...)

Échantillon de mockito javadoc :

ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
verify(mock, times(2)).doSomething(peopleCaptor.capture());

List<Person> capturedPeople = peopleCaptor.getAllValues();
assertEquals("John", capturedPeople.get(0).getName());
assertEquals("Jane", capturedPeople.get(1).getName());
697
proactif

Depuis Mockito 2.0, il est également possible d’utiliser une méthode statique Matchers.argThat (ArgumentMatcher) . Avec l’aide de Java 8, il est maintenant beaucoup plus propre et plus lisible d’écrire:

verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("OneSurname")));
verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("AnotherSurname")));

Si vous êtes attaché à la version Java inférieure, il n'y a pas de mal à dire:

verify(mockBar).doSth(argThat(new ArgumentMatcher<Employee>() {
        @Override
        public boolean matches(Object emp) {
            return ((Employee) emp).getSurname().equals("SomeSurname");
        }
    }));

Bien sûr, aucun de ceux-ci ne peut vérifier l'ordre des appels - pour lesquels vous devez utiliser InOrder :

InOrder inOrder = inOrder(mockBar);

inOrder.verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("FirstSurname")));
inOrder.verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("SecondSurname")));

S'il vous plaît jeter un oeil à mockito-Java8 projet qui permet de faire des appels tels que:

verify(mockBar).doSth(assertArg(arg -> assertThat(arg.getSurname()).isEqualTo("Surname")));
39
Maciej Dobrowolski

Si vous ne souhaitez pas valider tous les appels à doSomething(), vous ne pouvez utiliser que le dernier, ArgumentCaptor.getValue(). Selon le Mockito javadoc :

Si la méthode a été appelée plusieurs fois, elle renvoie la dernière valeur capturée

Donc cela fonctionnerait (supposons que Foo ait une méthode getName()):

ArgumentCaptor<Foo> fooCaptor = ArgumentCaptor.forClass(Foo.class);
verify(mockBar, times(2)).doSomething(fooCaptor.capture());
//getValue() contains value set in second call to doSomething()
assertEquals("2nd one", fooCaptor.getValue().getName());
25
lreeder

Vous pouvez également utiliser @Captor ArgumentCaptor annoté. Par exemple:

@Mock
List<String> mockedList;

@Captor
ArgumentCaptor<String> argCaptor;

@BeforeTest
public void init() {
    //Initialize objects annotated with @Mock, @Captor and @Spy.
    MockitoAnnotations.initMocks(this);
}

@Test
public void shouldCallAddMethodTwice() {
    mockedList.add("one");
    mockedList.add("two");
    Mockito.verify(mockedList, times(2)).add(argCaptor.capture());

    assertEquals("one", argCaptor.getAllValues().get(0));
    assertEquals("two", argCaptor.getAllValues().get(1));
}
8
Michał Stochmal

Avec les lambdas de Java 8, un moyen pratique consiste à utiliser

org.mockito.invocation.InvocationOnMock

when(client.deleteByQuery(anyString(), anyString())).then(invocationOnMock -> {
    assertEquals("myCollection", invocationOnMock.getArgument(0));
    assertThat(invocationOnMock.getArgument(1), Matchers.startsWith("id:"));
}
4
Anton Seredkin