Может ли Mockito захватывать аргументы метода, вызываемого несколько раз? - PullRequest
384 голосов
/ 12 мая 2011

У меня есть метод, который вызывается дважды, и я хочу захватить аргумент вызова второго метода.

Вот что я пробовал:

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()

Но я получаю исключение TooManyActualInvocations, поскольку Мокито считает, что doSomething следует вызывать только один раз.

Как мне проверить аргумент второго вызова doSomething?

Ответы [ 5 ]

683 голосов
/ 12 мая 2011

Я думаю, это должно быть

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

Образец из 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());
37 голосов
/ 15 января 2016

Начиная с Mockito 2.0 есть также возможность использовать статический метод Matchers.argThat (ArgumentMatcher) . С помощью Java 8 теперь стало намного чище и удобнее писать:

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

Если вы привязаны к более низкой версии Java, это также неплохо:

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

Конечно, никто из них не может проверить порядок звонков - для этого вы должны использовать 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")));

Пожалуйста, обратите внимание на проект mockito-java8 , который позволяет совершать такие звонки, как:

verify(mockBar).doSth(assertArg(arg -> assertThat(arg.getSurname()).isEqualTo("Surname")));
25 голосов
/ 08 октября 2013

Если вы не хотите проверять все вызовы на doSomething(), только последний, вы можете просто использовать ArgumentCaptor.getValue().Согласно Mockito javadoc :

Если метод был вызван несколько раз, он возвращает последнее захваченное значение

Так что это будет работать (предполагается, чтоFoo имеет метод 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());
8 голосов
/ 11 апреля 2018

Вы также можете использовать аннотированный @Captor ArgumentCaptor. Например:

@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));
}
3 голосов
/ 15 октября 2018

С лямбдами Java 8 удобным способом является использование

org.mockito.invocation.InvocationOnMock

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