Как проверить, что метод не был вызван с помощью Mockito?
Привет! Я пишу юнит-тесты для Java-приложения с использованием JUnit и Mockito. У меня есть сервис, который при определённых условиях не должен вызывать метод у зависимого объекта. Например, если пользователь не авторизован, то метод sendEmail() не должен вызываться. Как мне это проверить в тесте?
Вот упрощённый пример моего кода:
public class NotificationService {
private EmailService emailService;
public NotificationService(EmailService emailService) {
this.emailService = emailService;
}
public void processUser(User user) {
if (user.isActive()) {
emailService.sendEmail(user.getEmail(), "Welcome!");
}
}
}
Я написал тест для случая, когда пользователь активен — там я проверяю, что sendEmail() вызван с помощью verify(emailService).sendEmail(...). Но как написать тест для случая, когда пользователь НЕ активен (например, user.isActive() возвращает false)? Мне нужно убедиться, что sendEmail() не вызывается ни разу. Пробовал использовать verify(emailService, never()).sendEmail(...), но не уверен, что это правильный синтаксис. Может, есть другие способы?
Буду благодарен за примеры кода и объяснение. Заранее спасибо!
<<Использование verify(..., never()) — стандартный способ
Ваш подход с verify(emailService, never()).sendEmail(...) абсолютно правильный! Это самый простой и читаемый способ проверить, что метод не вызывался. Давайте разберём полный пример теста для вашего случая.
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;
public class NotificationServiceTest {
@Test
public void testProcessUser_inactiveUser_noEmailSent() {
// 1. Создаём мок
EmailService emailService = mock(EmailService.class);
NotificationService service = new NotificationService(emailService);
// 2. Создаём неактивного пользователя
User inactiveUser = mock(User.class);
when(inactiveUser.isActive()).thenReturn(false);
// 3. Вызываем тестируемый метод
service.processUser(inactiveUser);
// 4. Проверяем, что sendEmail НЕ вызывался
verify(emailService, never()).sendEmail(anyString(), anyString());
}
}
Ключевые моменты:
never()— это сокращение отtimes(0). Можно использовать и так:verify(emailService, times(0)).sendEmail(...).- Вместо конкретных аргументов используйте
anyString()илиany(), если вам не важно, с какими параметрами мог бы вызваться метод. Если вы укажете конкретные значения, тест будет проверять именно их отсутствие. - Важно:
verifyсработает, даже если метод вообще не вызывался. Если бы он вызывался, тест упал бы сTooManyActualInvocations.
Альтернатива: проверка на количество вызовов
Иногда удобнее использовать verify(emailService, times(0)).sendEmail(...) — это делает код более явным. Разницы с never() нет, это просто синтаксический сахар.
verify(emailService, times(0)).sendEmail(anyString(), anyString());
Что делать, если метод может вызываться несколько раз?
Если вы хотите проверить, что метод вызывался, но не с определёнными аргументами — используйте ArgumentCaptor или комбинацию verify с times(). Например:
// Проверяем, что sendEmail вызывался ровно 1 раз с любыми аргументами
verify(emailService, times(1)).sendEmail(anyString(), anyString());
// Проверяем, что НЕ вызывался с конкретным email
verify(emailService, never()).sendEmail("bad@example.com", anyString());
Распространённые ошибки
- Забыть вызвать метод: если вы не вызовете
service.processUser(inactiveUser), то проверкаnever()пройдёт, но тест будет бесполезен. - Проверять не тот мок: убедитесь, что вы передали мок в сервис, а не реальный объект.
- Использовать
verifyNoInteractions(): этот метод проверяет, что с моком вообще не было взаимодействий. Если у вас есть другие вызовы (например, кuser.isActive()), то тест упадёт. Используйте его только когда нужно проверить полное отсутствие вызовов всех методов.
Таким образом, ваш инстинкт использовать never() был верным. Это идиоматичный способ в Mockito для проверки отсутствия вызова.
Использование verifyNoInteractions() для полной проверки
Если вы хотите убедиться, что с моком вообще не было никаких взаимодействий (ни один метод не вызывался), можно использовать verifyNoInteractions(). Это более строгая проверка, чем never() для одного метода.
import static org.mockito.Mockito.*;
// В тесте:
service.processUser(inactiveUser);
verifyNoInteractions(emailService);
Когда это полезно:
- Если ваш метод не должен вызывать ни один метод мока при определённых условиях.
- Например, если при неактивном пользователе не только
sendEmail, но и другие методыEmailServiceне должны вызываться.
Важно: verifyNoInteractions упадёт, если был вызван хотя бы один метод мока, даже если это toString() или equals(). Поэтому используйте его осторожно. Если вы хотите игнорировать некоторые методы (например, геттеры), лучше придерживаться verify(..., never()) для конкретных методов.
Также есть метод verifyNoMoreInteractions(), который проверяет, что после указанных verify вызовов больше не было взаимодействий. Это может быть полезно для детальной верификации.