Применяем Mockito: когда использовать doAnswer и thenReturn

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Если требуется возвратить фиксированное значение, лучше всего использовать thenReturn(), оно обеспечивает концизную подстановку:

Java
Скопировать код
// Все как у верной собаки, её добыча всегда предсказуема
when(mock.someMethod()).thenReturn(value);

Когда необходимо добавить логику в ответ, выбирайте doAnswer():

Java
Скопировать код
// Более похоже на кота, предсказуемого, но способного удивить
doAnswer(invocation -> "ответ основан на " + invocation.getArgument(0))
    .when(mock).someMethod(any());
Кинга Идем в IT: пошаговый план для смены профессии

Искусство правильного выбора метода подстановки

Если нужно статическое значение — выбирайте thenReturn

Метод thenReturn() — ваш надежный спутник для фиксированной подстановки — он всецело обеспечит возврат того же результата:

Java
Скопировать код
// Это словно ежедневное наслаждение одним и тем же блюдом. Ожидаемо, но вкусно!
when(mock.myMethod()).thenReturn(myFixedValue);

Если метод вызывается в тесте множество раз, thenReturn() позволяет установить цепочку ответов на последующие вызовы:

Java
Скопировать код
// Все как в сериале с запланированными сюжетными поворотами
when(mock.myMethod()).thenReturn(firstValue, secondValue, thirdValue);

Для динамичных возвращаемых значений подойдет doAnswer

doAnswer() идеально справляется, когда необходим динамический ответ. С ним ваша подстановка способна формироваться на основе аргументов, как многогранное блюдо от шеф-повара:

Java
Скопировать код
// Это как создание коктейля: различные ингредиенты создают уникальный вкус
doAnswer(invocation -> {
    Integer input = invocation.getArgument(0);
    return input * 2; // Создаем ответ
}).when(mock).myMethod(anyInt());

doAnswer() также позволяет осуществлять дополнительные операции при вызове метода, например, изменять состояние или проверять аргументы.

Для методов с возратом void также подойдет doAnswer

При использовании методов void doAnswer() может воздействовать на методы, изменяющие состояние или генерирующие побочные эффекты, как в процессе строительства замка по эскизу:

Java
Скопировать код
// Это как приключение по карте, где заранее известны драконьи территории
doAnswer(invocation -> {
    System.out.println("Метод вызван с аргументами: " + Arrays.toString(invocation.getArguments()));
    return null; // Возвращаем null для методов void
}).when(mock).voidMethod(any());

Ненавязчивое наблюдение с помощью doAnswer

Хотите наблюдать за объектами без активизации их реального поведения? doAnswer() обеспечивает безопасную подмену методов, идеальную для тестов:

Java
Скопировать код
// Все как у ниндзя, оставаясь незамеченным
doAnswer(invocation -> "значение-заглушка").when(spy).myRealMethod();

Альтернатива в виде doReturn

doReturn() — это простой аналог thenReturn(), который стоит использовать, чтобы избежать выполнения логики реального метода:

Java
Скопировать код
// Это как тайный проход, спасающий от встречи с драконом
doReturn("значение-заглушка").when(spy).myRealMethod();

Визуализация

Давайте приведем основные различия между методами doAnswer и thenReturn в виде таблицы:

Метод MockitoКогда предпочтительнее его использовать
thenReturnПростые задачи. Фиксированный ответ
doAnswerСложные задачи. Динамические ответы

// thenReturn – Это как заказать стандартный бургер: без неожиданностей, ровно как и ожидали:

Java
Скопировать код
when(mock.someMethod()).thenReturn("фиксированный ответ");

// doAnswer – Это как создать собственный рецепт суши-ролла: творческий процесс с простором для импровизации:

Java
Скопировать код
when(mock.someMethod()).doAnswer(invocation -> {
    Object arg0 = invocation.getArgument(0);
    return "ответ создан на основе " + arg0; 
});

Все ясно на практических примерах

Имитация исключений при помощи doAnswer

doAnswer() позволяет смоделировать поведение кода при возникновении исключений. Это как тест-драйв для вашего кода:

Java
Скопировать код
doAnswer(invocation -> {
    if ("bad".equals(invocation.getArgument(0))) {
        throw new IllegalArgumentException("Пожалуйста, держитесь подальше от неприятностей!");
    }
    return "а вот и ответ";
}).when(mock).someMethod(anyString());

Имитация временных задержек

При необходимости смоделировать замедленную работу или временные задержки doAnswer() выполняет роль машины времени:

Java
Скопировать код
doAnswer(invocation -> {
    Thread.sleep(1000L); // Добавляем задержку для эффекта 
    return "Приветствие из будущего!";
}).when(mock).someMethod();

Сложная логика в возвращаемых значениях

Когда требуются дополнительные вычисления или результат зависит от внешних условий, doAnswer() дает простор для творчества:

Java
Скопировать код
doAnswer(invocation -> {
    if (someExternalCondition) {
        return "состояние достигнуто";
    }
    return "стандартный ответ";
}).when(mock).someMethod();

Полезные материалы

  1. Официальная документация Mockito по подстановке методовавторитетный источник для детального изучения темы.
  2. Юнит-тестирование с Mockito: обучающий материал — подробное руководство с продвинутыми техниками и советами.
  3. Примеры кода на Java для Mockito doAnswer – ProgramCreek — коллекция практичных примеров использования Mockito.doAnswer.
  4. Руководство по юнит-тестированию с Mockito | Toptal — обзор ежедневно применяемых методик работы с Mockito.
  5. Reddit – Обсуждение вопроса — отзывы о doAnswer против thenReturn в категории потокобезопасности.