Mockito能否捕获多次调用的方法的参数?


446

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

这是我尝试过的:

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

Answers:


781

我认为应该

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

来自嘲笑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());

3
您能否以此捕获doSomething()每个单独调用中传递的参数?
马特b

36
请注意,如果您执行以下操作: 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
asmaier 2014年

2
很好,但是如何测试两个不同类型的对象调用?例如ExecutorService.submit(new MyRunableImpl()); 然后ExecutorService.submit(new MyAnotherRunableImpl())?
莱昂2015年

如果需要处理@asmaier所述的情况,我会在此处发布答案:stackoverflow.com/a/36574817/1466267
SpaceTrucker

1
对于仍然想知道Leon问题答案的任何人,您都可以使用公共基类(Runnable),并在需要时对捕获的参数进行更具体的类型检查。
马修(Matthew)阅读了

50

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

请看一下嘲笑java8项目,该项目可以进行如下调用:

verify(mockBar).doSth(assertArg(arg -> assertThat(arg.getSurname()).isEqualTo("Surname")));

2
这是一个很好的技术。我目前正在得到一些相当神秘的输出:“想要但不被调用:/ n mockAppender.append(<索引管理器ut $$ lambda $ 5 9/1 3 1 9 5 1 0 1 6>);” -arg有一个CharSequence。您是否知道以任何方式使报告正确打印出“所需的”参数?
mike啮齿动物

@mikerodent如果您走创建实现ArgumentMatcher <T>的类的更冗长的路线,则可以修复隐秘的输出。在实现中覆盖toString方法将在嘲笑测试输出中提供您想要的任何消息。
诺亚所罗门

25

如果您不想验证所有对的调用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());

有什么办法可以捕捉这两个值?
哈尔斯(Hars)

9

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

6

使用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:"));
}

我看不到这比以前的方法更方便。我喜欢使用lambda,但是我不确定这是否是其中之一。
埃里克·威尔逊

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()访问单个(最后调用的)参数的值,以进行进一步的操作/检查或执行任何您想执行的操作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.