web-dev-qa-db-ja.com

Mockitoは複数回呼び出されたメソッドの引数を取得できますか?

私は二度呼ばれるメソッドを持っています、そして私は2番目のメソッド呼び出しの引数をとらえたいです。

これが私が試したものです:

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例外が発生します。

2番目のdoSomethingの呼び出しの引数を確認するにはどうすればいいですか?

377
Eric Wilson

私はそれがあるべきだと思います

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

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

doSomething()へのすべての呼び出しを検証したくない場合は、最後のものだけを検証したい場合は、ArgumentCaptor.getValue()を使用できます。 Mockito javadoc によると、

メソッドが複数回呼び出された場合は、最新の取得値を返します

それでこれはうまくいくでしょう(FoogetName()メソッドを持っていると仮定します):

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

@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));
}
8

Java 8のラムダでは、使うのが便利です。

org.mockito.invocation.InvocationOnMock

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