Формирование Мокито "грамматики"
Mockito выглядит как довольно приятный фреймворк для Java. Единственная проблема в том, что я не могу найти какую-либо конкретную документацию о лучших способах использования их API. Общие методы, используемые в тестах, включают в себя:
doXXX(???) : Stubber
when(T) : OngoingStubbing
then(T) : OngoingStubbing
verify(???) : T
given(T) : BDDOngoingStubbing
willXXX(???) : BDDStubber
Когда вы видите на практике примеры Mockito, вы видите такой код:
when(yourMethod()).thenReturn(5);
Из всех документов, которые я прочитал, я определил несколько "шаблонов" "грамматик" Мокито, полученных из последовательных вызовов этих методов вместе, как в примере выше. Некоторые общие шаблоны, которые я нашел:
Когда / Тогда: когда (yourMethod()). ThenReturn (5);
Given / Will: данный (yourMethod()). WillThrow (OutOfMemoryException.class);
Do / When: doReturn (7).when (yourMock.fizzBuzz ());
Will / Given / Do: willReturn (any ()). Данное (yourMethod()). DoNothing ();
Verify / Do: verify (yourMethod()). DoThrow(SomeException.class);
Я задыхаюсь, как правильно выбрать шаблон / комбинацию вызовов методов для моделирования моих тестовых случаев. Похоже, что вы можете объединить их в последовательные, казалось бы, бесконечные комбинации, и я не уверен, какой шаблон подходит для какой проблемы.
Может ли какой-нибудь гуру Мокито помочь пролить свет на то, какие шаблоны / комбинации методов Мокито используются для каких типов тестовых случаев (и почему)? Заранее спасибо!
3 ответа
У 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>());
Есть несколько недостатков when/thenReturn
, when/thenThrow
а также when/then
Синтаксисы. Например,
- В случае
when/thenReturn
, если возвращаемый тип является универсальным с подстановочным знаком, и вы хотите вернуть макет того же типа, вы не сможете избежать предупреждения компиляции. - Вы не можете использовать
when/thenThrow
а такжеwhen/then
для пустого метода. - Вы не можете использовать эти синтаксисы на шпионах Мокито.
- Вы можете только позвонить
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 не согласны.
На самом деле все выглядит намного проще, чем вы думали
REF: http://static.javadoc.io/org.mockito/mockito-core/2.7.12/org/mockito/Mockito.html
Проверить:
Чтобы использовать Mockito, вам необходимо понять одну базовую философию Mockito: "Окурки и проверки" разделены. Поэтому упомянутое вами "Подтверждение / Выполнение" фактически выполняет задание "Подтверждение", а остальные 4 "грамматики" предназначены для заглушки. Заглушки определяют, как макет объекта будет реагировать в другой ситуации. Проверка заключается в том, чтобы удостовериться, что макеты вызываются, как и ожидалось, при предыдущем вызове тестируемой системы (SUT).
Когда / Затем, Дано / Будет:
Затем речь идет о семьях "Когда" и "Дано". Вы можете просто рассматривать их как псевдонимы друг друга. "Данное" семейство добавлено в Mockito 1.8.x, чтобы оно выглядело более согласованным с практиками BDD.
DoXxx:
В нормальном случае мы в основном используем when(xxx).then(...)
(а также given(...).will(...)
) Однако в некоторых случаях синтаксис не работает. Наиболее очевидный случай, когда возвращаемый тип метода-заглушки имеет тип void. В таком случае when(mockObj.voidMethod()).thenThrow(anException)
не собирается компилировать. В качестве обходного пути создается альтернативный синтаксис Do/When, поэтому вы можете написать предыдущую строку как doThrow(anException).when(mockObj.voidMethod())