Формирование "грамматик" Mockito

Mockito похож на довольно приятную среду для stubbing/mocking для Java. Единственная проблема заключается в том, что я не могу найти какую-либо конкретную документацию по лучшим способам использования их API. Общие методы, используемые в тестах, включают:

doXXX(???) : Stubber
when(T) : OngoingStubbing
then(T) : OngoingStubbing
verify(???) : T
given(T) : BDDOngoingStubbing
willXXX(???) : BDDStubber

Когда вы видите примеры Mockito на практике, вы видите код типа:

when(yourMethod()).thenReturn(5);

Из всех документов, которые я прочитал, я определил несколько "шаблонов" "грамматик" Mockito, полученных из последовательного соединения этих методов, как показано выше. Некоторые общие шаблоны, которые я нашел, следующие:

Когда /Then:, когда (yourMethod()), затем возвратите (5);

Указано/будет: задано (yourMethod()). willThrow (OutOfMemoryException.class);

Do/When: doReturn (7).when(yourMock.fizzBuzz());

Will/Given/Do: willReturn (any()). given (yourMethod()). doNothing();

Проверить/выполнить: проверить (yourMethod()). doThrow (SomeException.class);

Что я задыхаюсь, так это то, как выбрать правильный шаблон/комбинацию вызовов методов для моделирования моих тестовых случаев. Кажется, вы можете объединить их вместе в казалось бы бесконечные комбо, и я не уверен, какой шаблон подходит именно для этой проблемы.

Может ли какой-нибудь Mockito Guru помочь пролить свет на то, какие шаблоны/комбинации методов Mockito используются для каких типов тестовых случаев (и почему)? Спасибо заранее!

Ответ 1

У Mockito часто есть несколько способов сделать что-то.

Я использую в основном:

// Setup expectations
when(object.method()).thenReturn(value);
when(object.method()).thenThrow(exception);
doThrow(exception).when(object.voidMethod());


// verify things
verify(object, times(2)).method();
verify(object, times(1)).voidMethod();

Я обнаружил, что могу сделать 95% того, что мне нужно, с этими тремя типами вызовов.

Кроме того, какую версию Mockito вы используете? Конструкции "даны" и "будут" в последней версии (1.9.0 +) отсутствуют

Однако есть случаи, когда я хочу, чтобы возвращаемое значение или исключение отвечали на ввод. В этом случае вы можете использовать интерфейс "Ответ" для проверки аргументов метода и возврата соответствующего значения.

public class ReturnFirstArg<T> implements Answer<T> {
    public T answer(InvocationOnMock invocation) {
        return invocation.getArguments()[0];
    }
}

when(object.method(7)).thenAnswer(new ReturnFirstArg<Integer>());

Ответ 2

Существует несколько недостатков синтаксиса when/thenReturn, when/thenThrow и when/then. Например,

  • В случае when/thenReturn, если тип возврата является общим с wildcard, и вы хотите вернуть макет того же типа, вы не сможете чтобы избежать предупреждения компиляции.
  • Вы не можете использовать when/thenThrow и when/then для метода void.
  • Вы не можете использовать эти синтаксисы для шпионов Mockito.
  • Вы можете вызывать только when один раз для каждой комбинации макетного объекта, метод и аргументы, если вы не назовете reset на макет.
  • Вызов when несколько раз для одной комбинации макета объект и метод, когда вы используете аргументы, могут привести к проблемам.

Я считаю, что эти случаи трудно запомнить. Поэтому вместо того, чтобы отслеживать, когда Синтаксисы when/thenReturn, when/thenThrow и when/then будут работать и не будут работать, я предпочитаю их полностью избегать в пользу альтернатив doReturn/when, doThrow/when и doAnswer/when. То есть, поскольку вам иногда понадобится doReturn/when, doThrow/when и doAnswer/when, и вы можете ВСЕГДА использовать эти методы, нет смысла изучать, как использовать when/thenReturn, when/thenThrow и when/then.

Обратите внимание, что doReturn, doThrow и doAnswer можно связать вместе так же, как thenReturn, thenThrow и then. То, что у них нет, - это вариант для возврата нескольких значений (или выбрасывание нескольких исключений или выполнение нескольких ответов) в течение одного вызова doReturn, doThrow и doAnswer. Но я считаю, что мне нужно делать это так редко, что это не имеет большого значения.

Есть еще один недостаток doReturn, который я считаю несущественным. Вы не проверяете время компиляции типа своего аргумента, как вы делаете с when/thenReturn. Поэтому, если вы неправильно зададите тип аргумента, вы не узнаете, пока не запустите свой тест. Честно говоря, мне все равно.

Итак, я использую Mockito уже более двух лет, и я считаю, что использование doReturn, doThrow и doAnswer является лучшей практикой Mockito. Другие пользователи Mockito не согласны.

Ответ 3

То, что на самом деле выглядит намного проще, чем вы думали

REF: http://static.javadoc.io/org.mockito/mockito-core/2.7.12/org/mockito/Mockito.html

Проверка

Чтобы использовать Mockito, вам нужно понять одну основную философию Mockito: Stubbing and Verification разделены. Таким образом, упомянутая вами "Verify/Do" фактически выполняет задание "Проверка", в то время как остальные 4 "грамматики" предназначены для укупорки. Stubbing определяет, как макет объекта будет реагировать в другой ситуации. Проверка заключается в том, чтобы убедиться, что mocks вызывается, как ожидалось, в предыдущем вызове в тестируемую систему (SUT).

Когда /Then, задано/будет:

Затем он приходит к семьям "Когда" и "Дано". Вы можете просто рассматривать их как псевдонимы друг друга. "Учитывая" семья добавлена ​​в Mockito 1.8.x, чтобы она выглядела более согласованной с практикой BDD.

DoXxx

В обычном случае мы в основном используем when(xxx).then(...)given(...).will(...)). Однако есть некоторые случаи, когда синтаксис не работает. Наиболее очевидным случаем является то, что тип возврата обрезанного метода недействителен. В таком случае when(mockObj.voidMethod()).thenThrow(anException) не собирается компилироваться. В качестве обходного пути создается альтернативный синтаксис Do/When, поэтому вы можете записать предыдущую строку как doThrow(anException).when(mockObj.voidMethod())