Ответ
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-тесты быстрыми, стабильными и сфокусированными исключительно на коде, который мы хотим проверить.
Ответ 18+ 🔞
Давай разберемся, что это за зверь такой — mock-объект. Представь, ты тестируешь какую-нибудь логику, а она, сука, лезет в базу данных, шлёт письма по почте или ещё какую дичь творит. И вот тебе уже терпения ноль ебать, потому что тесты тормозят как вязкая жижа, а ещё они хрупкие — чихни на сеть, и всё, тебе пи**ец.
Вот тут-то и появляется наш спаситель — mock. Это такая хитрая жопа, которая притворяется настоящей зависимостью (той самой базой или почтовиком), но на самом деле это полная липа. Её главный конёк — она умеет следить, как с ней общаются. То есть ты можешь потом проверить: «А вызывался ли метод sendEmail? А с какими аргументами? А сколько раз?». Это и есть верификация взаимодействий, без неё mock — просто манда с ушами.
Зачем это всё? Чтобы изолировать кусок кода, который ты проверяешь, от всего остального гребаного мира. Сосредоточиться на бизнес-логике, а не на том, что база данных сегодня с похмелья.
Смотри пример на Java (с Mockito), сейчас всё станет ясно: Допустим, у нас сервис уведомлений, который орет на почтовик, чтобы тот слал письма.
// Класс, который мы тестируем
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); // Вот тут он дергает зависимость
}
}
// А вот сам тест, где мы всё и накосячим
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-у и спрашиваем: «Ну что, чувак, тебя дергали?»
// Проверяем, что метод sendEmail вызвали ровно один раз с нужными параметрами.
verify(mockEmailSender, times(1))
.sendEmail(eq(testEmail), eq("Welcome!"), contains("Thank you"));
}
}
Чем mock не является, чтобы не было путаницы:
- Stub (Заглушка): Это просто тупая болванка, которая всегда отвечает «ок» или «ошибка». Она не следит за вызовами, ей да похуй.
- Fake (Фейк): Это уже почти рабочая, но упрощённая реализация. Типа репозитория в памяти вместо реальной БД. Используется для тестов покрупнее.
- Spy (Шпион): Это как будто ты подсадил к реальному объекту своего человека. Он и работает, и докладывает тебе, кто к нему обращался. Подозрение ебать чувствую к таким.
Короче, моки — это мощный инструмент, чтобы твои unit-тесты были быстрыми, стабильными и били точно в цель, а не во все дыры давалка.