Обзор
Фреймворк Mockito — это базовый фреймворк для модульного тестирования. В этой статье будут представлены его использование и функции, а также приведены соответствующие примеры в качестве справочного материала. Подробные бизнес-сценарии см. в написании модульного теста в проекте. В конце статьи также есть ссылки на соответствующие статьи о модульном тестировании, вы можете перейти и узнать о них больше.
После создания макетного объекта он запомнит все взаимодействия, а затем вы сможете выборочно проверить интересующие вас взаимодействия. Если проверка не пройдена, будет выдано исключение.
@Test
public void test1() {
final List mockList = Mockito.mock(List.class);
mockList.add("mock1");
mockList.get(0);
mockList.size();
mockList.clear();
// Метод проверки isuse (по умолчанию 1 раз)
Mockito.verify(mockList).add("mock1");
// Способ проверки использовался 1 раз
Mockito.verify(mockList, Mockito.times(1)).get(0);
// Способ проверки использовался хотя бы 1 раз
Mockito.verify(mockList, Mockito.atLeast(1)).size();
// Не указан метод аутентификации
Mockito.verify(mockList, Mockito.never()).contains("mock2");
// Метод проверки проверен не более 5 раз.
Mockito.verify(mockList, Mockito.atMost(5)).clear();
// Укажите таймаут вызова метода
Mockito.verify(mockList, timeout(100)).get(0);
// Количество раз, которое необходимо выполнить в течение указанного времени.
Mockito.verify(mockList, timeout(200).atLeastOnce()).size();
}
По умолчанию все функции возвращают значения. По умолчанию фиктивная функция возвращает значение null, пустую коллекцию или встроенный тип, обернутый типом объекта. Например, соответствующими типами объектов 0 и false являются Integer и Boolean;
После вызова функции тестовой заглушки она будет последовательно возвращать фиксированное значение;
Mockito не может работать, когда (…).thenReturn (…) для статических и финальных методов.
@Testpublic void test2() { //Статический импорт, уменьшите объём кода: import static org.mockito.Mockito.*;final ArrayList mockList = mock(ArrayList.class);// Установите возвращаемое значение вызова метода if(mockList.add("test2")).thenReturn(true); doReturn(true).when(mockList).add("test2"); System.out.println(mockList.add("test2")); //true// Установите вызов метода для выдачи исключения if(mockList.get(0)).thenThrow(new RuntimeException()); doThrow(new RuntimeException()).when(mockList).get(0); System.out.println(mockList.get(0)); //throw RuntimeException// Укладка без обратного метода doNothing().when(mockList).clear(); // Сделать тестовые заглушки для обратных вызовов (перехват возвращаемых методов) окончательными. Answer<String> answer = new Answer<String>() { @Overridepublic String answer(InvocationOnMock invocationOnMock) throws Throwable { final List mock = (List) invocationOnMock.getMock(); return"mock.size result => " + mock.size(); } }; when(mockList.get(1)).thenAnswer(answer); doAnswer(answer).when(mockList).get(1); System.out.println(mockList.get(1)); //mock.size result => 0// Для нескольких заглушек одного и того же метода преобладает последний if(mockList.get(2)).thenReturn("test2_1"); when(mockList.get(2)).thenReturn("test2_2"); System.out.println(mockList.get(2)); //test2_2 System.out.println(mockList.get(2)); //test2_2// Установите несколько вызовов одного и того же типа, когда(mockList.get(3)).thenReturn("test2_1", "test2_2"); when(mockList.get(3)).thenReturn("test2_1").thenReturn("test2_2"); System.out.println(mockList.get(3)); //test2_1 System.out.println(mockList.get(3)); //test2_2// Делайте тестовые заглушки для последовательных вызовов (создавайте тестовые заглушки для одного и того же вызова функции с разными возвращаемыми значениями или исключениями) if(mockList.get(4)).thenReturn("test2").thenThrow(new RuntimeException()); doReturn("test2").doThrow(new RuntimeException()).when(mockList).get(4); System.out.println(mockList.get(4)); //test2 System.out.println(mockList.get(4)); //throw RuntimeException// Без метода укладки, возврат к значению по умолчанию System.out.println(mockList.get(99)); //null}
Сопоставители параметров делают проверочные и тестовые заглушки более гибкими;
ради разумности Использованиесложныйиз Сопоставление параметров,использовать equals () и anyX () Сопоставитель сделает тестовый код более кратким и простым. Иногда вам приходится рефакторить свой код для использования equals () соответствовать или реализовать equals () Функции, которые помогут вам при тестировании;
Если вы используете средство сопоставления параметров, все параметры должны быть предоставлены средством сопоставления;
Поддержка сопоставления пользовательских параметров;
@Test
public void test3() {
final Map mockMap = mock(Map.class);
// Нормальное испытание на сваю
when(mockMap.get("key")).thenReturn("value1");
System.out.println(mockMap.get("key")); //value1
// Для гибкости используйте средство сопоставления параметров
when(mockMap.get(anyString())).thenReturn("value2");
System.out.println(mockMap.get(anyString())); //value2
System.out.println(mockMap.get("test_key")); //value2
System.out.println(mockMap.get(0)); //null
// При наличии нескольких входных параметров либо все они должны быть сопоставлены средством сопоставления параметров, либо ни один из них не должен использоваться, иначе возникнет исключение.
when(mockMap.put(anyString(), anyInt())).thenReturn("value3");
System.out.println(mockMap.put("key3", 3)); //value3
System.out.println(mockMap.put(anyString(), anyInt())); //value3
System.out.println(mockMap.put("key3", anyInt())); //аномальный
// поведенческая проверка, также поддерживает использование сопоставления параметров
verify(mockMap, atLeastOnce()).get(anyString());
verify(mockMap).put(anyString(), eq(3));
// Пользовательский инструмент сопоставления параметров
final ArgumentMatcher<ArgumentTestRequest> myArgumentMatcher = new ArgumentMatcher<ArgumentTestRequest>() {
@Override
public boolean matches(ArgumentTestRequest request) {
return
"name".equals(request.getName()) || "value".equals(request.getValue());
}
};
// Пользовательский инструмент сопоставления параметровиспользовать
final ArgumentTestService mock = mock(ArgumentTestService.class);
when(mock.argumentTestMethod(argThat(myArgumentMatcher))).thenReturn("success");
doReturn("success").when(mock).argumentTestMethod(argThat(myArgumentMatcher));
System.out.println(mock.argumentTestMethod(new ArgumentTestRequest("name", "value"))); // success
System.out.println(mock.argumentTestMethod(new ArgumentTestRequest())); //null
}
Порядок выполнения проверки очень гибкий — вам не нужно проверять все взаимодействия одно за другим, а только те объекты, которые вас интересуют;
Вы можете создавать объекты InOrder только из тех макетных объектов, порядок которых необходимо проверить;
@Test
public void test4() {
// Проверьте порядок выполнения нескольких методов одного и того же объекта.
final List mockList = mock(List.class);
mockList.add("first");
mockList.add("second");
final InOrder inOrder = inOrder(mockList);
inOrder.verify(mockList).add("first");
inOrder.verify(mockList).add("second");
// Проверка нескольких объектов и нескольких методов в порядке выполнения
final List mockList1 = mock(List.class);
final List mockList2 = mock(List.class);
mockList1.get(0);
mockList1.get(1);
mockList2.get(0);
mockList1.get(2);
mockList2.get(1);
final InOrder inOrder1 = inOrder(mockList1, mockList2);
inOrder1.verify(mockList1).get(0);
inOrder1.verify(mockList1).get(2);
inOrder1.verify(mockList2).get(1);
}
Некоторые пользователи могут часто использоватьverifyNoMoreInteractions(), даже в каждой тестовой функции. НоverifyNoMoreInteractions() не рекомендуется использовать в каждой тестовой функции;
verifyNoMoreInteractions() — это просто удобная проверка в интерактивном наборе тестов, когда нужно убедиться в отсутствии избыточных вызовов;
@Testpublicvoidtest5(){ // Убедитесь, что взаимодействие никогда не выполнялось окончательно. List mock = mock(List.class); mock.add("first"); verify(mock, never()).add("test5"); //проходить verify(mock, never()).add("first"); //аномальный// Убедитесь, что макетный объект не взаимодействовал с финальным List mock1 = mock(List.class); final List mock2 = mock(List.class); verifyZeroInteractions(mock1); //проходить verifyNoMoreInteractions(mock1, mock2); //проходить verifyZeroInteractions(mock, mock2); //аномальный// Примечание. Возможно, вам понадобится только проверить предыдущую логику, но добавление последней строки вызовет исключение. Рекомендуется проверять на уровне метода, например: Never() //; При проверке наличия избыточных вызовов вы можете использовать этот метод. Вот так: окончательный List mockList = mock(List.class); mockList.add("one"); mockList.add("two"); verify(mockList).add("one"); // проходить verify(mockList, never()).get(0); //проходить verifyZeroInteractions(mockList); //аномальный}
Уведомление! Перед запуском тестовой функции необходимо вызвать следующий код, который обычно размещается в базовом классе тестового класса или средства запуска тестов:
MockitoAnnotations.initMocks(this);
Также доступно использование встроенного runner: MockitoJUnitRunner или rule : MockitoRule;
// заменять mock(ArgumentTestService.class) создать макет объекта;
@Mock
private ArgumentTestService argumentTestService;
// Если модификация аннотации изобъекта изменена на переменные-члены, определение @Mock изmockобъект будет автоматически внедрено;
@InjectMocks
private MockitoAnnotationServiceImpl mockitoAnnotationService;
@Test
public void test6() {
// Уведомление! Перед запуском тестовой функции необходимо вызвать следующий код. Обычно он размещается в тестовом классе, базовом классе или тесте. в бегуне;
MockitoAnnotations.initMocks(this);
when(argumentTestService.argumentTestMethod(new ArgumentTestRequest())).thenReturn("success");
System.out.println(argumentTestService.argumentTestMethod(new ArgumentTestRequest())); //success
System.out.println(mockitoAnnotationService.mockitoAnnotationTestMethod()); //null
}
Шпионский объект может быть создан для реального объекта. Когда вы используете этот шпионский объект, реальный объект также будет вызываться, если только его функция не заглушена;
Используйте шпионские объекты как можно меньше и будьте осторожны при их использовании. Например, шпионские объекты можно использовать для работы с устаревшим кодом;
stub В грамматике также предусмотрены разделы mock Метод может вызывать настоящий метод; полностью mock: Содержимое, упомянутое выше, полностью издевательский, то есть созданный mock объект, реальный объект не имеет значения, издевательство Методы объекта по умолчанию являются базовыми реализациями и возвращают базовые типы. Может быть создан на основе интерфейсов и классов реализации. mock объект. часть mock: так называемыйчасть издевательский, то есть созданный mock Объект основан на реальном объекте, макет Все методы объекта по умолчанию используют методы реального объекта, если только stub После этого будет stub будет преобладать. Создать на основе класса реализации mock объект, иначе нет stub В этом случае при вызове реального метода возникнет исключение. Примечание: Mockito Прокси-функция не вызывается для реального объекта, на самом деле она копирует реальный объект. Поэтому, если вы сохраняете реальный объект и взаимодействуете с ним, не ждите правильных результатов от мониторинга объекта. Когда вы вызываете метод отслеживаемого объекта, который еще не был stub Соответствующая функция реального объекта вызываться не будет, и вы не увидите никаких эффектов на реальный объект.
@Testpublic void test7() { // stubpartmock (на самом деле в заглушке он называется «использовать»). Примечание. Вам необходимо издеваться над классом реализации, иначе произойдет окончательное исключение. StubTestService stubTestService = mock(StubTestServiceImpl.class);when(stubTestService.stubTestMethodA("paramA")).thenCallRealMethod(); doCallRealMethod().when(stubTestService).stubTestMethodB(); System.out.println(stubTestService.stubTestMethodA("paramA")); //stubTestMethodA is called, param = paramA System.out.println(stubTestService.stubTestMethodB()); //stubTestMethodB is called System.out.println(stubTestService.stubTestMethodC()); //null// spyчастьmockfinal LinkedList<String> linkedList = new LinkedList(); final LinkedList spy = spy(linkedList); spy.add("one"); spy.add("two"); doReturn(100).when(spy).size(); when(spy.get(0)).thenReturn("one_test"); System.out.println(spy.size()); //100 System.out.println(spy.get(0)); //one_test System.out.println(spy.get(1)); //two// Шпиона можно сравнить с АОП. В шпионе, поскольку по умолчанию вызывается реальный метод, второй способ записи не эквивалентен первому способу записи, и этот способ записи не рекомендуется. doReturn("two_test").when(spy).get(2); when(spy.get(2)).thenReturn("two_test"); //аномальный java.lang.IndexOutOfBoundsException: Index: 2, Size: 2 System.out.println(spy.get(2)); //two_test// spyобъект — это просто реальный Объекткопировать, настоящий Объект Изменить не влияет на spyобъектfinal List<String> arrayList = new ArrayList<>(); final List<String> spy1 = spy(arrayList); spy1.add(0, "one"); System.out.println(spy1.get(0)); //one arrayList.add(0, "list1"); System.out.println(arrayList.get(0)); //list1 System.out.println(spy1.get(0)); //one// Если вы хотите вызвать настоящий метод после заглушки метода, вы можете сбросить (шпионить) финал ArrayList<String> arrayList1 = new ArrayList<>(); final ArrayList<String> spy2 = spy(arrayList1); doReturn(100).when(spy2).size(); System.out.println(spy2.size()); //100 reset(spy2); System.out.println(spy2.size()); //0}
Различие между макетным объектом и шпионским объектом:
Mockito.mockingDetails(someObject).isMock();
Mockito.mockingDetails(someObject).isSpy();
@Mock
private StubTestService stubTestService;
@Spy
private StubTestServiceImpl stubTestServiceImpl;
@Spy
private StubTestService stubTestServiceImpl1 = new StubTestServiceImpl();
@Test
public void test8() {
MockitoAnnotations.initMocks(this);
// макетный объект возвращается к состоянию по умолчанию
System.out.println(stubTestService.stubTestMethodB()); //null
// шпионский объект вызывает настоящий метод
System.out.println(stubTestServiceImpl.stubTestMethodC()); //stubTestMethodC is called
System.out.println(stubTestServiceImpl1.stubTestMethodA("spy")); //stubTestMethodA is called, param = spy
// Различие между макетным объектом и шпионским объектом
System.out.println(mockingDetails(stubTestService).isMock()); //true
System.out.println(mockingDetails(stubTestService).isSpy()); //false
System.out.println(mockingDetails(stubTestServiceImpl).isSpy()); //true
}
В некоторых сценариях необходимо не только проверить возвращаемое значение и вызов метода, но также проверить параметры, переданные методу после серии взаимодействий. Затем мы можем использовать средство захвата параметров, чтобы захватить параметры, переданные методу, для проверки, чтобы увидеть, соответствует ли он нашим требованиям. ArgumentCaptor представлять проходить ArgumentCaptor Объект forClass (Class ArgumentCaptor из Api argument.capture () Параметры метода захвата argument.getValue () Получите значение параметра метода. Если метод вызывается несколько раз, он вернет последнее значение параметра. argument.getAllValues () После многократного вызова метода он возвращает несколько значений параметров.
@Test
public void test9() {
List mock = mock(List.class);
List mock1 = mock(List.class);
mock.add("John");
mock1.add("Brian");
mock1.add("Jim");
// Получить параметры метода
ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);
verify(mock).add(argument.capture());
System.out.println(argument.getValue()); //John
// Позвоните несколько раз, чтобы получить последнее
ArgumentCaptor argument1 = ArgumentCaptor.forClass(String.class);
verify(mock1, times(2)).add(argument1.capture());
System.out.println(argument1.getValue()); //Jim
// Получить все параметры звонка
System.out.println(argument1.getAllValues()); //[Brian, Jim]
}
@Mock
private List<String> captorList;
@Captor
private ArgumentCaptor<String> argumentCaptor;
@Test
public void test10() {
MockitoAnnotations.initMocks(this);
captorList.add("cap1");
captorList.add("cap2");
System.out.println(captorList.size());
verify(captorList, atLeastOnce()).add(argumentCaptor.capture());
System.out.println(argumentCaptor.getAllValues());
}
@Test
public
void
test11()
{
final ArrayList arrayList = mock(ArrayList.class);
arrayList.add("one");
arrayList.add("two");
verify(arrayList, описание("size() не была вызвана")).size();
// org.mockito.exceptions.base.MockitoAssertionError: size() не вызывается
verify(arrayList, timeout(200).times(3).description("Проверка не удалась")).add(anyString());
//org.mockito.exceptions.base.MockitoAssertionError: Аутентификация не удалась
}
@Test
public void test12(){
// Создать макет объекта, использовать возврат по умолчанию
final ArrayList mockList = mock(ArrayList.class);
System.out.println(mockList.get(0)); //null
// Эта реализация сначала пробует глобальную конфигурацию, если глобальной конфигурации нет, она отвечает по умолчанию, что возвращает 0, пустой набор, ноль и т. д.
// Эталонная конфигурация возврата: ReturnsEmptyValues
mock(ArrayList.class, Answers.RETURNS_DEFAULTS);
// ReturnsSmartNulls сначала пытается вернуть нормальные значения (0, пустая коллекция, пустая строка и т. д.), а затем пытается вернуть SmartNull.
// Если в конечном итоге он вернет объект, он просто вернет ноль. Обычно используется при работе с устаревшим кодом.
// Эталонная конфигурация возврата: ReturnsMoreEmptyValues
mock(ArrayList.class, Answers.RETURNS_SMART_NULLS);
// Без стабизметода будет вызван настоящий метод.
// Примечание 1. Когда заглушка имитирует использование (mock.getSomething ()) .thenReturn (fakeValue) вызовет метод из. для часть имитирует рекомендуемый синтаксис usedoReturn.
// Примечание 2. Если моделирование представляет собой сериализацию и десериализацию, то этот ответ не будет понимать общие метаданные.
mock(ArrayList.class, Answers.CALLS_REAL_METHODS);
// Глубокая заглушка для вложения Объектмокков. Ссылка: https://www.cnblogs.com/Ming8006/p/6297333.html.
mock(ArrayList.class, Answers.RETURNS_DEEP_STUBS);
// ReturnsMocks сначала пытается вернуть нормальные значения (0, пустую коллекцию, пустую строку и т. д.), а затем пытается вернуть макеты.
// Если тип возвращаемого значения не может быть имитирован (например, он является окончательным), возвращается значение null.
mock(ArrayList.class, Answers.RETURNS_MOCKS);
// После вызова метода макетного Объекта вы можете вернуться самостоятельно (аналогично режиму конструктора)
mock(ArrayList.class, Answers.RETURNS_SELF);
// Пользовательский возврат
final Answer<String> answer = new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
return
"test_answer";
}
};
final ArrayList mockList1 = mock(ArrayList.class, answer);
System.out.println(mockList1.get(0)); //test_answer
}