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

Mockito ArgumentMatchers

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

1. Обзор

В этом руководстве показано, как использовать ArgumentMatcher и чем он отличается от ArgumentCaptor .

Ознакомление с фреймворком Mockito можно найти в этой статье .

2. Зависимости Maven

Нам нужно добавить один артефакт:

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.21.0</version>
<scope>test</scope>
</dependency>

Последнюю версию Mockito можно найти на Maven Central .

3. Сопоставители аргументов

Можно настроить mock-метод различными способами. Один из них — возвращать фиксированные значения:

doReturn("Flower").when(flowerService).analyze("poppy");

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

Но , возможно, нам нужно реагировать на более широкий диапазон значений или на заранее неизвестные значения .

Во всех этих сценариях мы можем настроить наши фиктивные методы с помощью `` сопоставителей аргументов : ``

when(flowerService.analyze(anyString())).thenReturn("Flower");

Теперь, благодаря сопоставителю аргументов anyString , результат будет одинаковым независимо от того, какое значение мы передаем для анализа. ArgumentMatchers позволяет нам гибко проверять или заглушать.

Если метод имеет более одного аргумента, невозможно использовать ArgumentMatchers только для некоторых аргументов . Mockito требует, чтобы вы предоставили все аргументы либо с помощью совпадений , либо с точными значениями.

Следующий пример — неправильный подход к этому:

abstract class FlowerService {
public abstract boolean isABigFlower(String name, int petals);
}

FlowerService mock = mock(FlowerService.class);

when(mock.isABigFlower("poppy", anyInt())).thenReturn(true);

Чтобы исправить это и оставить имя String «маковым», как хотелось бы, мы будем использовать eq matcher :

when(mock.isABigFlower(eq("poppy"), anyInt())).thenReturn(true);

Есть еще два момента, на которые следует обратить внимание при использовании сопоставителей :

  • Мы не можем использовать их в качестве возвращаемого значения , требуется точное значение при заглушке вызовов.
  • Наконец, мы не можем использовать сопоставители аргументов вне проверки или заглушки.

В последнем случае Mockito обнаружит неуместный аргумент и выдаст исключение InvalidUseOfMatchersException .

Плохим примером может быть:

String orMatcher = or(eq("poppy"), endsWith("y"));
verify(mock).analyze(orMatcher);

Способ реализации приведенного выше кода:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

Mockito также предоставляет AdditionalMatchers для реализации общих логических операций («не», «и», «или») над ArgumentMatchers , которые соответствуют как примитивным, так и непримитивным типам:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

4. Пользовательское сопоставление аргументов

Создание нашего сопоставителя может быть полезным для выбора наилучшего возможного подхода для данного сценария и создания теста высочайшего качества , который является чистым и удобным в сопровождении.

Например, у нас может быть MessageController , который доставляет сообщения. Он получит MessageDTO и на его основе создаст сообщение , которое будет доставлено MessageService .

Наша проверка будет простой, убедитесь, что мы вызывали MessageService ровно 1 раз с любым Message:

verify(messageService, times(1)).deliverMessage(any(Message.class));

Поскольку Message создается внутри тестируемого метода `` , мы вынуждены использовать любой в качестве сопоставителя .

Этот подход не позволяет нам проверять данные внутри Message , которые могут отличаться от данных внутри MessageDTO .

По этой причине мы собираемся реализовать собственный сопоставитель аргументов:

public class MessageMatcher implements ArgumentMatcher<Message> {

private Message left;

// constructors

@Override
public boolean matches(Message right) {
return left.getFrom().equals(right.getFrom()) &&
left.getTo().equals(right.getTo()) &&
left.getText().equals(right.getText()) &&
right.getDate() != null &&
right.getId() != null;
}
}

Чтобы использовать наш сопоставитель, нам нужно изменить наш тест и заменить любой на argThat :

verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));

Теперь мы знаем, что наш экземпляр Message будет иметь те же данные, что и наш MessageDTO .

5. Пользовательское сопоставление аргументов и ArgumentCaptor

Оба метода — настраиваемые сопоставления аргументов и ArgumentCaptor — могут использоваться для проверки того, что определенные аргументы были переданы мокам.

Однако ArgumentCaptor может подойти лучше, если нам нужно, чтобы он утверждал значения аргументов для завершения проверки, или если наш пользовательский сопоставитель аргументов вряд ли будет использоваться повторно . `` ``

Пользовательские сопоставления аргументов через ArgumentMatcher обычно лучше подходят для заглушек.

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

В этой статье мы рассмотрели функцию Mockito , ArgumentMatcher и ее отличие от ArgumentCaptor .

Как всегда, полный исходный код примеров доступен на GitHub .