Ответ
Mock-объект — это специально созданный объект-заглушка, который имитирует поведение реальной зависимости в модульном тесте. Его ключевая особенность — возможность проверки взаимодействий: тест может утверждать, что определенные методы мока были вызваны с ожидаемыми аргументами нужное количество раз.
Зачем это нужно? Чтобы изолировать тестируемый модуль (например, сервис) от внешних систем (база данных, API, файловая система) и сосредоточиться на проверке его бизнес-логики.
Пример на Java с Mockito:
Допустим, у нас есть NotificationService, который зависит от EmailSender.
// Класс, который мы тестируем
public class NotificationService {
private EmailSender emailSender;
public NotificationService(EmailSender emailSender) {
this.emailSender = emailSender;
}
public void sendWelcomeEmail(String userEmail) {
String subject = "Welcome!";
String body = "Thank you for registering.";
emailSender.sendEmail(userEmail, subject, body); // Взаимодействие с зависимостью
}
}
// Тест с использованием Mock
import static org.mockito.Mockito.*;
class NotificationServiceTest {
@Test
void sendWelcomeEmail_ShouldCallEmailSenderWithCorrectParameters() {
// 1. Создаем mock-объект
EmailSender mockEmailSender = mock(EmailSender.class);
NotificationService service = new NotificationService(mockEmailSender);
String testEmail = "user@example.com";
// 2. Выполняем действие
service.sendWelcomeEmail(testEmail);
// 3. Верификация (VERIFY): проверяем, что взаимодействие произошло
// Это главное отличие Mock от Stub. Мы проверяем, был ли вызван метод sendEmail
// с конкретными аргументами ровно один раз.
verify(mockEmailSender, times(1))
.sendEmail(eq(testEmail), eq("Welcome!"), contains("Thank you"));
}
}
Отличие от других типов тестовых дублеров:
- Stub: Простая заглушка, которая возвращает предопределенные данные. Не занимается верификацией вызовов.
- Fake: Упрощенная, но рабочая реализация (например, репозиторий, хранящий данные в памяти
HashMapвместо реальной БД). Используется для интеграционного тестирования. - Spy: Частичный mock, который оборачивает реальный объект, позволяя отслеживать его вызовы и при необходимости подменять поведение отдельных методов.
Использование моков делает unit-тесты быстрыми, стабильными и сфокусированными исключительно на коде, который мы хотим проверить.