
В Java void методы не возвращают значения, поэтому стандартные подходы Mockito с when().thenReturn() для них не применимы. Для имитации поведения void методов используется цепочка doNothing(), doThrow() или doAnswer(), которая позволяет контролировать реакции метода при тестировании.
Mockito позволяет создавать мок-объекты классов и интерфейсов, чтобы изолировать тестируемый код от зависимостей. При работе с void методами важно правильно настроить поведение мока, особенно если метод может выбрасывать исключения или изменять состояние внешних объектов.
Для тестирования вызовов void метода необходимо использовать verify(), которая фиксирует, был ли вызван метод с конкретными аргументами и сколько раз. Это критично при проверке взаимодействий между сервисами и компонентами без выполнения реальной логики.
Если void метод принимает аргументы, Mockito предоставляет возможность комбинировать doAnswer() с ArgumentCaptor, чтобы анализировать входные значения и задавать кастомное поведение. Такой подход облегчает написание интеграционных и unit-тестов с точной имитацией сложных сценариев.
При настройке поведения void методов важно учитывать порядок вызовов, обработку исключений и возвращаемые эффекты на внешние объекты. Корректное использование doNothing(), doThrow() и verify() позволяет создавать надежные тесты, которые отражают реальные сценарии работы приложения без запуска полной бизнес-логики.
Подключение Mockito к проекту и настройка зависимостей

Для использования Mockito в проекте на Java необходимо добавить библиотеку в систему сборки. В Maven это делается через зависимость mockito-core версии 5.0 и выше, с указанием области test:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
В Gradle подключение выглядит так: testImplementation 'org.mockito:mockito-core:5.5.0'. Для работы с аннотациями @Mock и @InjectMocks требуется дополнительная интеграция с JUnit 5 через mockito-junit-jupiter:
testImplementation 'org.mockito:mockito-junit-jupiter:5.5.0'
После добавления зависимостей необходимо инициализировать мок-объекты. В JUnit 5 это выполняется с помощью аннотации @ExtendWith(MockitoExtension.class), что исключает необходимость вызова MockitoAnnotations.openMocks(this) вручную. Такой подход обеспечивает корректную привязку моков к тестируемому классу и упрощает настройку поведения void методов.
Важно проверять совместимость версий Mockito и JUnit, так как использование устаревших зависимостей может привести к ошибкам и некорректной работе аннотаций. Для проектов на Spring рекомендуется подключать spring-boot-starter-test, который включает актуальные версии Mockito и JUnit, что сокращает конфигурацию.
Создание мок-объекта для класса с void методом

Для имитации поведения класса с void методом в Mockito используется функция mock(). Например, если есть класс NotificationService с методом sendEmail(), мок создается так: NotificationService notificationMock = mock(NotificationService.class);. Это позволяет вызвать метод без выполнения реальной логики.
Если требуется работать с аннотациями, достаточно объявить поле класса с @Mock и использовать MockitoExtension в JUnit 5:
@Mock
private NotificationService notificationMock;
Важно помнить, что вызовы void методов по умолчанию ничего не делают, но Mockito фиксирует их вызовы для последующей проверки через verify(). При необходимости можно задать конкретное поведение с помощью doNothing(), doThrow() или doAnswer(), что особенно полезно при тестировании исключений и побочных эффектов.
При создании мока для класса с несколькими void методами рекомендуется явно настраивать каждый метод, поведение которого важно для теста. Это снижает вероятность непредвиденных вызовов и упрощает анализ тестов при возникновении ошибок.
Использование doNothing() для void методов

Метод doNothing() в Mockito применяется для void методов, когда необходимо подавить их выполнение и предотвратить побочные эффекты. Это особенно актуально для методов, изменяющих состояние базы данных, файловой системы или внешних сервисов.
Пример использования:
doNothing().when(notificationMock).sendEmail(anyString());
В этом случае вызов sendEmail() не выполняет реальную отправку письма, но Mockito фиксирует факт вызова для последующей проверки.
Рекомендации по применению doNothing():
- Использовать для void методов, которые не должны менять состояние тестируемой среды.
- Комбинировать с verify() для проверки аргументов и количества вызовов.
- Применять с аргументами через matchers, например
anyInt()илиanyString(), чтобы обрабатывать любые значения. - Не использовать без необходимости, если метод имеет критическое логическое значение для теста – в таких случаях предпочтительнее doAnswer().
Для методов с несколькими вызовами можно комбинировать doNothing() с цепочкой вызовов, чтобы задавать разное поведение на каждый вызов:
doNothing().doThrow(new RuntimeException()).when(notificationMock).sendEmail(anyString());
Таким образом первый вызов будет игнорироваться, а второй выбросит исключение, что позволяет моделировать реальные сценарии взаимодействия с void методами.
Применение doThrow() для имитации исключений

Метод doThrow() в Mockito позволяет замокать void методы так, чтобы они выбрасывали исключения при вызове. Это необходимо для тестирования обработки ошибок и сценариев с нестандартным поведением.
Пример использования:
doThrow(new RuntimeException("Ошибка отправки письма"))
.when(notificationMock)
.sendEmail(anyString());
В данном случае каждый вызов sendEmail() с любым аргументом приведет к выбросу RuntimeException, что позволяет проверять блоки try-catch в тестируемом коде.
Рекомендации по применению doThrow():
- Использовать для проверки корректной обработки исключений без выполнения реальной логики метода.
- Комбинировать с verify() для подтверждения вызова метода перед возникновением исключения.
- Можно задавать разные исключения на последовательные вызовы, используя цепочку:
doThrow(new IOException()).doThrow(new RuntimeException()). - Применять с аргументами через matchers, например
any()илиeq(), чтобы точно контролировать поведение при конкретных входных данных. - Не использовать doThrow() для методов, где требуется выполнение побочных эффектов, иначе тест потеряет смысл.
Настройка поведения void метода с аргументами

Для void методов, принимающих аргументы, Mockito позволяет задавать поведение с учетом конкретных значений или диапазонов. Это выполняется через doNothing(), doThrow() и doAnswer() в сочетании с matchers, такими как any(), eq() или argThat().
Пример подавления выполнения метода с любым аргументом:
doNothing().when(notificationMock).sendEmail(anyString());
Пример выброса исключения для конкретного аргумента:
doThrow(new RuntimeException())
.when(notificationMock)
.sendEmail(eq("blocked@example.com"));
Для сложной логики используется doAnswer(), которая позволяет анализировать входные аргументы и задавать динамическое поведение:
doAnswer(invocation -> {
String email = invocation.getArgument(0);
if(email.endsWith("@test.com")) throw new RuntimeException();
return null;
}).when(notificationMock).sendEmail(anyString());
Рекомендации по настройке поведения:
- Использовать точные matchers для критичных аргументов, чтобы избежать ложных срабатываний.
- Применять doAnswer() при необходимости проверки значений и создания условных сценариев.
- Комбинировать с verify() для подтверждения правильности вызова метода с нужными аргументами.
- Избегать глобального doNothing() для всех аргументов, если метод имеет важные побочные эффекты.
Проверка вызовов void метода через verify()

Метод verify() в Mockito используется для контроля вызовов void методов и проверки аргументов. Это позволяет убедиться, что метод был вызван ожидаемое количество раз и с нужными параметрами.
Пример проверки одного вызова:
verify(notificationMock).sendEmail("user@example.com");
Проверка количества вызовов выполняется с помощью times() или never():
verify(notificationMock, times(2)).sendEmail(anyString());
verify(notificationMock, never()).sendEmail("blocked@example.com");
Для проверки порядка вызовов используется InOrder:
InOrder inOrder = inOrder(notificationMock);
inOrder.verify(notificationMock).connect();
inOrder.verify(notificationMock).sendEmail(anyString());
Рекомендации по использованию verify():
- Применять verify() после вызова тестируемого метода, чтобы фиксировать реальные вызовы void метода.
- Использовать matchers для аргументов, если точные значения заранее неизвестны или переменны.
- Комбинировать с doThrow() и doAnswer(), чтобы проверять корректную обработку исключений и побочных эффектов.
- Следить за тем, чтобы verify() не дублировал тестируемую логику, а фиксировал только взаимодействие с моками.
Объединение нескольких настроек для одного void метода

Mockito позволяет комбинировать несколько настроек для одного void метода, чтобы моделировать последовательные действия или различные сценарии вызовов. Это делается через цепочки doNothing(), doThrow() и doAnswer().
Пример последовательного поведения:
doNothing()
.doThrow(new RuntimeException("Ошибка на втором вызове"))
.doNothing()
.when(notificationMock)
.sendEmail(anyString());
В этом случае первый вызов метода ничего не делает, второй выбрасывает исключение, а третий снова игнорируется.
Для наглядного сравнения поведения можно использовать таблицу:
| Вызов | Действие метода |
|---|---|
| 1 | doNothing() – метод выполняется без побочных эффектов |
| 2 | doThrow() – выбрасывается RuntimeException |
| 3 | doNothing() – метод игнорируется |
Рекомендации по объединению настроек:
- Четко определять порядок вызовов, чтобы тесты оставались предсказуемыми.
- Использовать doAnswer() для сложной логики на определенных вызовах, например с анализом аргументов.
- Комбинировать с verify() для проверки, что каждый вызов произошел с нужным поведением.
- Не создавать слишком длинные цепочки для одного метода, чтобы тесты оставались читаемыми и поддерживаемыми.
Вопрос-ответ:
Почему обычный when().thenReturn() не подходит для void методов в Mockito?
Метод when().thenReturn() работает только с методами, которые возвращают значение. Void методы ничего не возвращают, поэтому попытка использовать стандартный синтаксис приведет к ошибке Mockito. Для void методов используются doNothing(), doThrow() или doAnswer(), которые позволяют задать поведение метода при вызове без возвращаемого значения.
Как проверить, что void метод был вызван с конкретными аргументами несколько раз?
Для проверки вызовов void метода используется verify(). Например, verify(mockObject, times(3)).processData("input") проверит, что метод processData был вызван три раза с аргументом «input». Также можно использовать matchers, такие как anyString() или eq(), если требуется гибкость при сравнении аргументов.
Можно ли замокать void метод так, чтобы он выбрасывал исключение только при определенном аргументе?
Да, это выполняется с помощью doThrow() в сочетании с matchers. Например: doThrow(new RuntimeException()).when(mock).sendEmail(eq("blocked@example.com")). В этом случае исключение будет выброшено только при передаче конкретного аргумента, остальные вызовы метода будут игнорироваться или выполняться по другой настройке.
Как комбинировать несколько действий для одного void метода в тестах?
Mockito позволяет задавать последовательное поведение через цепочки вызовов doNothing(), doThrow() и doAnswer(). Например: doNothing().doThrow(new RuntimeException()).doNothing().when(mock).sendEmail(anyString()). Первый вызов будет игнорироваться, второй выбросит исключение, третий снова не будет иметь эффекта. Это помогает тестировать сценарии с разными результатами при последовательных вызовах метода.
