Mockito可以捕获多次调用方法的参数吗?

时间:2011-05-12 16:57:08

标签: java unit-testing mocking mockito

我有一个被调用两次的方法,我想捕获第二个方法调用的参数。

这是我尝试过的:

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例外情况,因为Mockito认为只应调用doSomething一次。

如何验证doSomething的第二次调用的参数?

6 个答案:

答案 0 :(得分:668)

我认为应该是

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

答案 1 :(得分:37)

自从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")));

答案 2 :(得分:25)

如果您不想验证对doSomething()的所有来电,只有最后一次,您可以使用ArgumentCaptor.getValue()。根据{{​​3}}:

如果多次调用该方法,则返回最新捕获的值

所以这可行(假设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());

答案 3 :(得分:8)

您也可以使用@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));
}

答案 4 :(得分:3)

对于Java 8的lambda,一种便捷的方法是使用

org.mockito.invocation.InvocationOnMock

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

答案 5 :(得分:0)

首先:您应该始终导入static static,这样,代码将更具可读性(更直观)-下面的代码示例要求它能正常工作:

import static org.mockito.Mockito.*;

在verify()方法中,您可以传递ArgumentCaptor以确保在测试中执行,而可以传递ArgumentCaptor来评估参数:

ArgumentCaptor<MyExampleClass> argument = ArgumentCaptor.forClass(MyExampleClass.class);
verify(yourmock, atleast(2)).myMethod(argument.capture());

List<MyExampleClass> passedArguments = argument.getAllValues();

for (MyExampleClass data : passedArguments){
    //assertSometing ...
    System.out.println(data.getFoo());
}

可以通过arguments.getAllValues()方法访问测试期间所有传递的参数的列表。

可以通过arguments.getValue()访问单个(最后调用的)参数的值,以进行进一步的操作/检查或执行任何您想做的事情。