← Назад к вопросам

Что такое моки и стабы в тестировании? В чём разница?

1.2 Junior🔥 191 комментариев
#Тестирование

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Моки и стабы в тестировании: основные концепции и различия

В контексте тестирования, особенно unit-тестирования (модульного тестирования), моки (mock objects) и стабы (stub objects) являются разновидностями тестовых дублёров (test doubles). Они используются для замены реальных зависимостей тестируемого объекта (например, внешних сервисов, сложных классов, баз данных) с целью создания контролируемого и изолированного тестового окружения. Основная цель — проверить поведение самого тестируемого модуля, а не его зависимостей.

Определение и роль стабов (Stubs)

Стабы — это объекты, которые предоставляют заранее заданные, фиксированные ответы на вызовы методов во время теста. Их главная задача — убрать зависимость от внешнего поведения и обеспечить тестируемый код необходимыми данными "как будто" из реальной системы.

  • Функция: Замена реального объекта для предоставления предопределённых ответов.
  • Когда использовать: Когда нужно просто "протолкнуть" тестовые данные через систему, чтобы проверить реакцию тестируемого модуля на эти данные.
  • Пример сценария: Тестирование сервиса, который зависит от UserRepository. Стаб UserRepository всегда возвращает заранее созданного пользователя с определённым ID, независимо от того, существует он в реальной БД или нет.
  • Философия: "Не важно, что происходит снаружи; вот данные, которые ты получишь. Проверяй своё поведение на них."

Пример кода стаба в PHP (используя PHPUnit):

// Стаб для репозитория пользователей
$userRepositoryStub = $this->createStub(UserRepository::class);
$userRepositoryStub->method('findById')
    ->willReturn(new User(1, 'John Doe'));

// Тестируемый сервис использует стаб вместо реального репозитория
$userService = new UserService($userRepositoryStub);
$result = $userService->getUserProfile(1);

$this->assertEquals('John Doe', $result->getName());

Определение и роль моков (Mocks)

Моки — это объекты, которые не только предоставляют фиксированные ответы (как стабы), но также позволяют устанавливать ожидания (expectations) относительно того, как они будут взаимодействовать с тестируемым кодом. Тест с моком проверяет, что тестируемый модуль вызвал методы мока ожидаемым образом (определённое количество раз, с конкретными аргументами).

  • Функция: Замена реального объекта для проверки взаимодействия между тестируемым объектом и зависимостью.
  • Когда использовать: Когда нужно убедиться, что тестируемый модуль правильно использует свою зависимость (например, вызывает метод сохранения в БД именно один раз).
  • Пример сценария: Тестирование сервиса отправки уведомлений. Мок EmailSender проверяет, что метод send() был вызван точно один раз с конкретным адресом электронной почты.
  • Философия: "Я не только дам тебе нужный ответ, но и буду следить, как ты меня используешь. Если ты нарушишь ожидания — тест провалится."

Пример кода мока в PHP (используя PHPUnit):

// Мок для сервиса отправки email
$emailSenderMock = $this->createMock(EmailSender::class);
// Устанавливаем ожидание: метод send должен быть вызван один раз с конкретным аргументом
$emailSenderMock->expects($this->once())
    ->method('send')
    ->with('client@example.com');

// Тестируемый сервис использует мок
$notificationService = new NotificationService($emailSenderMock);
$notificationService->sendWelcomeEmail('client@example.com');

// Проверка ожиданий выполняется автоматически PHPUnit после вызова метода

Ключевые различия между моками и стабами

  1. Цель использования:
    *   **Стаб**: Подмена зависимости для предоставления *данных* (состояния). Проверяется *реакция* тестируемого объекта на эти данные.
    *   **Мок**: Подмена зависимости для проверки *взаимодействия* (поведения). Проверяется *способ использования* тестируемого объекта этой зависимости.

  1. Фокус проверки:
    *   **Стаб**: Фокус на **состояние** (state verification). Мы проверяем, что после выполнения операции результат (выходные данные, состояние объекта) соответствует ожиданиям.
    *   **Мок**: Фокус на **поведение** (behavior verification). Мы проверяем, что были произведены ожидаемые вызовы методов зависимого объекта.

  1. Настройка в тесте:
    *   **Стаб**: Настраивается для возврата конкретных значений. Обычно не проверяет, как его методы были вызваны.
    *   **Мок**: Настраивается с ожиданиями (`expects()`). Тест провалится, если эти ожидания не будут выполнены (например, метод не был вызван или был вызван с неправильными аргументами).

Практический совет и заключение

В современных фреймворках для тестирования (таких как PHPUnit) граница между моками и стабами часто размыта технически — один и тот же метод (createMock() или createStub()) может быть настроен как для простой подмены (стаб), так и для проверки взаимодействия (мок). Однако концептуальное различие остаётся критически важным для написания чистых и понятных тестов.

  • Используйте стаб, когда ваш тест сосредоточен на том, что делает система (на её конечном результате или состоянии).
  • Используйте мок, когда ваш тест должен проверить, как система делает что-то (какие именно вызовы она совершает к внешним компонентам).

Понимание этой разницы помогает избежать чрезмерного использования моков там, где достаточно стаба, что ведет к более надежным и менее хрупким тестам.

Что такое моки и стабы в тестировании? В чём разница? | PrepBro