Формирование "грамматик" 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())