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

161

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

Рекомендуется использовать ArgumentCaptor с проверкой, но не с заглушкой.

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

Не могу сказать
источник
1
Супер короткое и хорошее объяснение здесь: dzone.com/articles/…
Benj

Ответы:

271

Предполагая следующий метод для тестирования:

public boolean doSomething(SomeClass arg);

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

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);
assertThat(argumentCaptor.getValue(), equalTo(expected));

Потому что вы можете просто использовать matcher во время заглушки:

when(someObject.doSomething(eq(expected))).thenReturn(true);

Но проверка - это другая история. Если ваш тест должен гарантировать, что этот метод был вызван с определенным аргументом, используйте, ArgumentCaptorи это тот случай, для которого он предназначен:

ArgumentCaptor<SomeClass> argumentCaptor = ArgumentCaptor.forClass(SomeClass.class);
verify(someObject).doSomething(argumentCaptor.capture());
assertThat(argumentCaptor.getValue(), equalTo(expected));
Rorick
источник
Спасибо за ответ. У меня есть вопрос. В третьем блоке кода мы знаем, что true возвращается только тогда, когда ожидаемый передается doSomething. Но когда true возвращается во втором блоке кода? Или someObject всегда возвращает true для someMethod в этом случае?
Не могу сказать
Хм, я полагаю, вы имели в виду «Но когда истина возвращается в третьем блоке кода?». В третьем блоке кода нам просто не нужно возвращаемое значение, и пусть оно будет значением по умолчанию. Для логического значения это falseне так true.
Рорик
Нет, я посчитал все блоки серого фона как блоки кода. Включая первый лайнер. Я имел в виду строку когда (someObject.doSomething (argumentsCaptor.capture ())). ThenReturn (true);
Не могу сказать
Ах, прости. Да, в этом случае true будет возвращено всегда.
Рорик
3
не уверен, что причина "не использовать с заглушкой" является простой причиной. matchers не дают нам фактический ожидаемый аргумент (только тип) и приводят к тому, что все в порядке с прохождением тестов, несмотря на аргументы, которые могут быть неверными.
DTC
0

Линия

when(someObject.doSomething(argumentCaptor.capture())).thenReturn(true);

будет делать так же, как

when(someObject.doSomething(Matchers.any())).thenReturn(true);

Таким образом, использование argumentsCaptor.capture (), когда заглушка не имеет добавленной стоимости. Использование Matchers.any () лучше показывает, что происходит на самом деле, и, следовательно, лучше для удобства чтения. С параметром argumentsCaptor.capture () вы не можете прочитать, какие аргументы действительно совпадают. И вместо использования any (), вы можете использовать более конкретные сопоставления, когда у вас есть больше информации (класс ожидаемого аргумента), чтобы улучшить ваш тест.

И еще одна проблема: если при аргументе при использовании аргумента использовать аргументapCaptor.capture () становится неясно, сколько значений следует ожидать после проверки. Мы хотим получить значение во время проверки, а не во время создания заглушки, потому что в этот момент еще нет значения для захвата. Так что же захватчики аргументов захватывают при захвате метода? или это ничего не захватывает? У меня нет ответа на этот вопрос. Я считаю, что это неопределенное поведение, и я не хочу использовать неопределенное поведение.

Стефан Монделерс
источник
0

Гипотетически, если поиск натолкнул вас на этот вопрос, то вы, вероятно, хотите это:

doReturn(someReturn).when(someObject).doSomething(argThat(argument -> argument.getName().equals("Bob")));

Зачем? Потому что, как и я, ты ценишь время и не собираешься реализовывать .equalsего ради сценария единого теста.

И 99% тестов разваливаются с нулем, возвращенным из Mock, и при разумном дизайне вы сможете избежать возврата nullлюбой ценой, использовать Optionalили переходить в Kotlin. Это подразумевает, что verifyне нужно использовать это часто, и ArgumentCaptors просто слишком утомительны для написания.

баклажан
источник