首页 文章

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

提问于
浏览
345

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

这是我尝试过的:

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 第二次调用的参数?

5 回答

  • 618

    我认为应该是

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

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

    如果您不想验证对 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

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

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

相关问题