java - una - ¿Puede Mockito capturar argumentos de un método llamado varias veces?
metodos en java netbeans (5)
Con las lambdas de Java 8, una forma conveniente es usar
org.mockito.invocation.InvocationOnMock
when(client.deleteByQuery(anyString(), anyString())).then(invocationOnMock -> {
assertEquals("myCollection", invocationOnMock.getArgument(0));
assertThat(invocationOnMock.getArgument(1), Matchers.startsWith("id:"));
}
Tengo un método al que se llama dos veces y quiero capturar el argumento de la segunda llamada de método.
Esto es lo que he intentado:
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()
Pero recibo una excepción TooManyActualInvocations
, ya que Mockito piensa que solo se debe llamar a Algo una vez.
¿Cómo puedo verificar el argumento de la segunda convocatoria de doSomething
?
Creo que debería ser
verify(mockBar, times(2)).doSomething(...)
Muestra 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());
Desde Mockito 2.0 también existe la posibilidad de usar el método estático Matchers.argThat(ArgumentMatcher) . Con la ayuda de Java 8 ahora es mucho más limpio y más fácil de escribir:
verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("OneSurname")));
verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("AnotherSurname")));
Si estás atado a una versión más baja de Java, no hay nada malo:
verify(mockBar).doSth(argThat(new ArgumentMatcher<Employee>() {
@Override
public boolean matches(Object emp) {
return ((Employee) emp).getSurname().equals("SomeSurname");
}
}));
Por supuesto, ninguno de ellos puede verificar el orden de las llamadas, para lo cual debe usar 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")));
Por favor, eche un vistazo al proyecto mockito-java8 que hace posible hacer llamadas como:
verify(mockBar).doSth(assertArg(arg -> assertThat(arg.getSurname()).isEqualTo("Surname")));
Si no desea validar todas las llamadas a doSomething()
, solo la última, solo puede usar ArgumentCaptor.getValue()
. Según el mockito javadoc :
Si el método se llamó varias veces, devuelve el último valor capturado
Así que esto funcionaría (asume que Foo
tiene un método 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());
También puede utilizar ArgumentCaptor anotado en @Captor. Por ejemplo:
@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));
}