Перейти к основному содержимому

Мок-методы Mockito

· 4 мин. чтения

Задача: Сумма двух чисел

Напишите функцию twoSum. Которая получает массив целых чисел nums и целую сумму target, а возвращает индексы двух чисел, сумма которых равна target. Любой набор входных данных имеет ровно одно решение, и вы не можете использовать один и тот же элемент дважды. Ответ можно возвращать в любом порядке...

ANDROMEDA

1. Обзор

В этом руководстве мы проиллюстрируем различные варианты использования стандартных статических фиктивных методов Mockito API.

Как и в других статьях, посвященных фреймворку Mockito (например , Mockito Verify или Mockito When/Then ), класс MyList , показанный ниже, будет использоваться в качестве соавтора, который будет имитироваться в тестовых примерах:

public class MyList extends AbstractList<String> {
@Override
public String get(int index) {
return null;
}

@Override
public int size() {
return 1;
}
}

2. Простое издевательство

Самый простой перегруженный вариант фиктивного метода — это вариант с одним параметром для фиктивного класса:

public static <T> T mock(Class<T> classToMock)

Мы будем использовать этот метод, чтобы смоделировать класс и установить ожидание:

MyList listMock = mock(MyList.class);
when(listMock.add(anyString())).thenReturn(false);

Затем мы выполним метод на макете:

boolean added = listMock.add(randomAlphabetic(6));

Следующий код подтверждает, что мы вызвали метод добавления в макете. Вызов возвращает значение, соответствующее ожиданиям, которые мы установили ранее:

verify(listMock).add(anyString());
assertThat(added, is(false));

3. Издевательство над именем Мока

В этом разделе мы рассмотрим другой вариант фиктивного метода, который предоставляется с аргументом, указывающим имя фиктивного метода:

public static <T> T mock(Class<T> classToMock, String name)

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

Чтобы убедиться, что сообщение об исключении, выдаваемое при неудачной проверке, включает предоставленное имя макета, мы будем полагаться на реализацию JUnit интерфейса TestRule , ExpectedException , и включим его в тестовый класс:

@Rule
public ExpectedException thrown = ExpectedException.none();

Мы будем использовать это правило для обработки исключений, вызванных тестовыми методами.

В следующем коде мы создадим макет для класса MyList и назовем его myMock :

MyList listMock = mock(MyList.class, "myMock");

Затем мы установим ожидание метода макета и выполним его:

when(listMock.add(anyString())).thenReturn(false);
listMock.add(randomAlphabetic(6));

Мы создадим преднамеренно неудачную проверку, которая должна вызвать исключение с сообщением, содержащим информацию о макете. Чтобы сделать это, нам сначала нужно установить ожидания для исключения:

thrown.expect(TooLittleActualInvocations.class);
thrown.expectMessage(containsString("myMock.add"));

Мы ожидаем, что следующая проверка завершится ошибкой и выдаст исключение:

verify(listMock, times(2)).add(anyString());

Вот сообщение о выброшенном исключении:

org.mockito.exceptions.verification.TooLittleActualInvocations:
myMock.add(<any>);
Wanted 2 times:
at com.foreach.mockito.MockitoMockTest
.whenUsingMockWithName_thenCorrect(MockitoMockTest.java:...)
but was 1 time:
at com.foreach.mockito.MockitoMockTest
.whenUsingMockWithName_thenCorrect(MockitoMockTest.java:...)

Как мы видим, сообщение об исключении включает имя мока, что будет полезно для поиска точки отказа в случае неудачной проверки.

4. Насмешка с ответом

Здесь мы продемонстрируем использование варианта макета , в котором мы настроим стратегию ответов макета на взаимодействие во время создания. Сигнатура этого фиктивного метода в документации Mockito выглядит следующим образом:

public static <T> T mock(Class<T> classToMock, Answer defaultAnswer)

Начнем с определения реализации интерфейса Answer :

class CustomAnswer implements Answer<Boolean> {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return false;
}
}

Мы будем использовать класс CustomAnswer выше для создания макета:

MyList listMock = mock(MyList.class, new CustomAnswer());

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

boolean added = listMock.add(randomAlphabetic(6));

Следующая проверка и утверждение подтверждают, что фиктивный метод с аргументом Answer работал должным образом:

verify(listMock).add(anyString());
assertThat(added, is(false));

5. Издевательство с помощью MockSettings

Последний фиктивный метод, который мы рассмотрим в этой статье, — это вариант с параметром типа MockSettings . Мы используем этот перегруженный метод для предоставления нестандартного макета.

Существует несколько пользовательских настроек, поддерживаемых методами интерфейса MockSettings , например, регистрация прослушивателя для вызовов методов в текущем макете с помощью invocationListeners , настройка сериализации с помощью serializable , указание экземпляра для слежения с помощью spiedInstance , настройка Mockito для попытки использовать конструктор. при создании макета с помощью useConstructor и т. д.

Для удобства мы будем повторно использовать класс CustomAnswer , представленный в предыдущем разделе, для создания реализации MockSettings , определяющей ответ по умолчанию.

Объект MockSettings создается фабричным методом:

MockSettings customSettings = withSettings().defaultAnswer(new CustomAnswer());

Мы будем использовать этот объект настройки при создании нового макета:

MyList listMock = mock(MyList.class, customSettings);

Как и в предыдущем разделе, мы вызовем метод добавления экземпляра MyList и убедимся, что фиктивный метод с аргументом MockSettings работает должным образом:

boolean added = listMock.add(randomAlphabetic(6));
verify(listMock).add(anyString());
assertThat(added, is(false));

6. Заключение

В этой статье мы подробно рассмотрели фиктивный метод Mockito. Реализацию этих примеров и фрагментов кода можно найти в проекте GitHub .