我有一个被调用两次的方法,我想捕获第二个方法调用的参数。
这是我尝试过的:
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
的第二次调用的参数?
我认为应该是
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());
由于 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")));
CharSequence
。你知道有什么方法可以让报告正确打印出“想要的”arg吗?
如果您不想验证对 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());
您还可以使用 @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 的 lambda,一种方便的方法是使用
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() 访问单个(最后调用的)参数的值,以进行进一步的操作/检查或您想做的任何事情。
doSomething()
的参数吗?Person person = new Person("John"); doSomething(person); person.setName("Jane"); doSomething(person);
捕获的参数将两次相同(因为实际上它是同一个人对象),所以capturedPeople.get(0).getName() == capturedPeople.get(1).getName() == "Jane"
,另请参阅 groups.google.com/forum/#!msg/mockito/KBRocVedYT0/5HtARMl9r2wJ。Runnable
),如果需要,对捕获的参数进行更具体的类型检查。