Как использовать ArgumentCaptor для stubbing?

В Mockito документация и javadocs говорится:

Рекомендуется использовать ArgumentCaptor с верификацией, но не с помощью stubbing.

но я не понимаю, как ArgumentCaptor можно использовать для stubbing. Может ли кто-нибудь объяснить приведенный выше оператор и показать, как ArgumentCaptor можно использовать для stubbing или предоставить ссылку, которая показывает, как это можно сделать?

Ответ 1

Предположим, что у вас есть следующий метод:

public boolean doSomething(SomeClass arg);

Документация Mockito говорит, что вы не должны использовать этот способ:

ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);

// invoke SUT (System Under Test)

SomeClass expected = // some expected value
assertThat(argumentCaptor.getValue(), equalTo(expected));

Причина проста: вы можете использовать совпадение во время stubbing:

SomeClass expected = // some expected value
when(someObject.doSomething(eq(expected))).thenReturn(true);

// invoke SUT

Но проверка может быть другой. Скажем, вам не нужно заглушать doSomething. Вы вполне довольны возвращаемым значением по умолчанию из mock (это будет false). Поэтому вам не нужно заглушить. Но ваш тест должен гарантировать, что этот метод был вызван, и его аргумент был правильным. Затем вы используете ArgumentCaptor, и это тот случай, для которого он предназначен:

// invoke SUT

ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
verify(someObject).doSomething(argumentCaptor.capture());
SomeClass expected = // some expected value

assertThat(argumentCaptor.getValue(), equalTo(expected));

Ответ 2

Он не говорит, что он может быть использован для stubbing, он говорит с stubbing.

Таким образом, вы можете использовать аргумент с помощью stubbing следующим образом:

ArgumentCaptor<SomeOtherObject> argumentCaptor = argumentCaptor.forClass(SomeOtherObject.class);

stub(someObject.doSomething(someParameter)).toReturn(someOtherObject);

someObject.doSomething(someParameter);

verify(someObject).doSomething(argumentCaptor.capture());

Хотя, вероятно, это не очень хорошая идея. Возможно, это потому, что это может вызвать проблемы, если doSomething() вызывается с другим параметром, чем с некоторым параметром.