Mockito ArgumentMatchers

Mockito ArgumentMatchers

1. обзор

В этом руководстве показанhow to use the ArgumentMatcher and how it differs from the ArgumentCaptor.

Для введения в структуру Mockito, пожалуйста, обратитесь кto this article.

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

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


    org.mockito
    mockito-core
    2.21.0
    test

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

3. ArgumentMatchersс

Возможна настройка макета метода различными способами. Одним из них является возвращение фиксированных значений:

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

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

Ноmaybe we need to respond to a wider range of values or beforehand unknown values.

Во всех этих сценарияхwe can configure our mocked methods with argument*matchers*:

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

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

Если у метода более одного аргумента,it isn’t possible to use ArgumentMatchers for only some of the arguments. Mockito требует, чтобы вы предоставили все аргументы либоmatchers, либо точные значения.

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

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);

При использованииmatchers  следует учитывать еще два момента:

  • We can’t use them as a return value, точное значение требуется при заглушке вызовов

  • Наконец,we can’t use argument matchers outside of verification or stubbing

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

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

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

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

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

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

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

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

Созданиеour matcher can be good to select the best possible approach for a given scenario and produce highest quality test, чистого и поддерживаемого.

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

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

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

Посколькуthe Message is constructed inside the method under test, мы вынуждены использоватьany какmatcher.

Этот подход не позволяет нам проверять данные внутриMessage,which can be different compared to the data inside MessageDTO.

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

public class MessageMatcher implements ArgumentMatcher {

    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;
    }
}

To use our matcher, we need to modify our test and replace any by argThat:

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

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

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

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

ОднакоArgumentCaptor may be a better fit if we need it to assert on argument values для завершения проверкиor our custom argument matcher is not likely to be reused.

Custom argument matchers черезArgumentMatcher обычно лучше для заглушки.

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

В этой статье мы рассмотрели особенностиMockito, ArgumentMatcher и их отличие отArgumentCaptor..

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