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的参数?

363076 次浏览

我觉得应该是

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

示例来自5 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());

如果您不想验证对doSomething()的所有调用,只验证最后一个调用,您可以只使用ArgumentCaptor.getValue()。根据5 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());

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

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

使用Java 8的lambdas,一种方便的方法就是使用它

org.mockito.invocation.InvocationOnMock


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

首先:你应该总是导入mockito 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());
}

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

单个(最后调用的)参数的值可以通过argument. getvalue()进行进一步的操作/检查或任何你想做的事情。