Что такое Mock в контексте модульного тестирования?

Ответ

Mock (Мок-объект) — это тестовый двойник, который имитирует поведение реальной зависимости, позволяя изолировать тестируемый модуль и проверять его взаимодействие с этой зависимостью.

Основное назначение:

  1. Изоляция: Замена внешних сервисов (БД, API, файловой системы).
  2. Верификация: Проверка, что тестируемый код корректно вызывает методы зависимости с ожидаемыми аргументами.
  3. Задание поведения: Определение ответов на вызовы методов (возврат значений, выброс исключений).

Пример с Mockito (Java):

// Зависимость
public class PaymentGateway {
    public boolean charge(double amount) { /* ... */ }
}

// Тест
@Test
public void orderService_ShouldChargeCustomer() {
    // 1. Создание мока
    PaymentGateway mockGateway = Mockito.mock(PaymentGateway.class);
    // 2. Задание поведения
    Mockito.when(mockGateway.charge(100.0)).thenReturn(true);

    // 3. Использование мока в тестируемом сервисе
    OrderService service = new OrderService(mockGateway);
    boolean success = service.placeOrder(100.0);

    // 4. Проверка состояния и взаимодействия
    assertTrue(success);
    Mockito.verify(mockGateway).charge(100.0); // Верификация вызова
}

Отличие от других тестовых двойников:

  • Stub (Заглушка): Пассивный объект, только возвращает предопределённые данные.
  • Spy (Шпион): Обёртка над реальным объектом, позволяющая отслеживать вызовы и при необходимости подменять поведение.
  • Mock (Мок): Активно используется для верификации взаимодействий.

Ответ 18+ 🔞

А, ну это про моки, блядь! Ну, слушай, сейчас разжуём, как бабушка котлету. Это ж тестовые куклы, которые подсовывают твоему коду вместо настоящих, ебаных, зависимостей.

Представь, ты тестируешь сервис заказа. А он, сука, лезет в базу данных и шлёт запросы в платёжный шлюз. И если этот шлюз сейчас сдох, то все твои тесты накроются медным тазом, а ты будешь сидеть и думать: «Чё за пиздец? Я же просто логику заказа проверяю!». Вот чтобы этого не было, и нужны эти самые моки.

Зачем они, эти мартышлюшки?

  1. Изоляция, ёпта. Подменяешь реальную базу данных, внешний апишник или файловую систему на послушную куклу. Теперь твой код варится в собственном соку, и ему похуй, что там во внешнем мире творится.
  2. Верификация, блядь. Это главная фишка! Ты не только подменяешь поведение, но и потом можешь проверить: «А вызывал ли мой сервис метод charge(100.0) у платёжки? И ровно один раз? И с правильной суммой?». Если не вызывал — значит, логика говно, и тест упадёт.
  3. Задание поведения. Говоришь моку: «Слушай сюда, когда у тебя вызовут метод findById(5), верни вот этот объект пользователя. А когда вызовут findById(999), кинь исключение NotFoundException, нахуй». И он послушно будет это делать.

Смотри, как это выглядит в коде (на примере Mockito, это как стандарт де-факто):

// Вот наша реальная зависимость, которую мы будем мокать
public class PaymentGateway {
    public boolean charge(double amount) { /* ...ходит в интернет, общается с банком... */ }
}

// А вот сам тест
@Test
public void orderService_ShouldChargeCustomer() {
    // 1. Создаём мок. Вот он, наш актёр на замену.
    PaymentGateway mockGateway = Mockito.mock(PaymentGateway.class);

    // 2. Задаём ему сценарий. Говорим: «Чувак, если тебя попросят зарядить ровно сотню, ты верни `true`».
    Mockito.when(mockGateway.charge(100.0)).thenReturn(true);

    // 3. Подсовываем эту подставу в наш сервис и запускаем логику.
    OrderService service = new OrderService(mockGateway);
    boolean success = service.placeOrder(100.0);

    // 4. А теперь — самое интересное! Проверяем и результат, и факт общения.
    assertTrue(success); // Стандартная проверка состояния
    Mockito.verify(mockGateway).charge(100.0); // А это верификация! «Докажи, что метод charge(100.0) был вызван!»
}

Чем мок отличается от других подставных уродов?

  • Stub (Заглушка): Это тупой, блядь, болван. Его задача — просто молча вернуть то, что ты попросил. Он не следит ни за чем. Как бутылка с запиской.
  • Spy (Шпион): Это уже хитрая жопа. Обычно это обёртка над реальным объектом. Ты даёшь ему работать по-настоящему, но при этом можешь подсматривать, какие методы вызывались, и влезать, чтобы подменить поведение в отдельных местах. Настоящий стукач.
  • Mock (Мок): А это — главный провокатор. Его основная работа — следить за взаимодействием и яростно докладывать тебе, если что-то пошло не по сценарию. «Ага! Ты обещал вызвать save() два раза, а вызвал один! Пидор несчастный!».

Короче, моки — это твои глаза и уши внутри теста, которые следят, чтобы код не просто работал, но и правильно общался с окружающим миром. Без них — как без рук, только в мире юнит-тестов.