В чем разница между stub и mock?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между Stub и Mock в тестировании
В контексте модульного тестирования и тестовой изоляции, stub и mock являются двумя важнейшими типами тестовых двойников (test doubles), но они служат разным целям и используются в разных сценариях. Оба помогают изолировать тестируемый код от зависимостей, но принципиально отличаются по своему поведению и назначению.
Ключевое концептуальное отличие
Stub (заглушка) — это объект с предопределёнными ответами на вызовы методов. Его основная цель — предоставить тестируемому коду необходимые данные или состояния, чтобы сценарий теста мог выполниться. Stub не проверяет, как он используется тестируемым кодом.
Mock (имитация) — это объект, который регистрирует вызовы своих методов. Его главная цель — проверить взаимодействие между тестируемым кодом и зависимостью. Mock знает, какие методы должны быть вызваны, с какими параметрами и сколько раз.
Детальное сравнение
Stub: Предоставление данных
- Пассивный объект: просто возвращает жестко заданные значения
- Фокус на состоянии: помогает установить необходимое состояние для теста
- Нет проверки вызовов: не следит за тем, как и сколько раз его методы вызываются
- Простая реализация: обычно создается вручную или с помощью минимальных средств фреймворка
Пример stub на Python:
class UserRepositoryStub:
"""Stub для репозитория пользователей"""
def get_user(self, user_id):
# Всегда возвращает предопределенного пользователя
return User(id=user_id, name="Test User", email="test@example.com")
def is_user_active(self, user_id):
# Всегда возвращает True для упрощения теста
return True
# В тесте
def test_user_greeting():
repo = UserRepositoryStub()
service = UserService(repo)
result = service.get_greeting(123)
assert result == "Hello, Test User!"
Mock: Проверка взаимодействий
- Активный объект: ожидает определенных вызовов и проверяет их
- Фокус на поведении: проверяет, как тестируемый код взаимодействует с зависимостями
- Верификация вызовов: явно проверяет, какие методы были вызваны, с какими параметрами
- Использование фреймворков: обычно создается с помощью библиотек (unittest.mock, Moq, Mockito)
Пример mock на Python с unittest.mock:
from unittest.mock import Mock
def test_send_notification():
"""Тест проверяет, что сервис правильно вызывает отправку уведомления"""
# Создаем mock для сервиса уведомлений
notification_mock = Mock()
notification_mock.send_email.return_value = True
# Внедряем mock в тестируемый сервис
user_service = UserService(notification_mock)
user_service.notify_user(123, "Welcome message")
# ВЕРИФИКАЦИЯ: проверяем, что метод был вызван правильно
notification_mock.send_email.assert_called_once_with(
user_id=123,
message="Welcome message",
subject="Notification"
)
Практические различия в использовании
Когда использовать Stub:
- Нужно предоставить тестовые данные для зависимостей
- Требуется симулировать определенное состояние системы
- Зависимость возвращает значения, но их вызов не является частью Assert
- Тестируемый код только получает данные от зависимости
Когда использовать Mock:
- Необходимо проверить, что тестируемый код правильно вызывает методы зависимости
- Нужно убедиться в определенной последовательности вызовов
- Требуется проверить количество вызовов методов
- Важно убедиться, что методы вызываются с правильными параметрами
Сравнительная таблица
| Аспект | Stub | Mock |
|---|---|---|
| Основная цель | Предоставление данных | Проверка взаимодействий |
| Проверка вызовов | Нет | Да (критически важно) |
| Сложность | Простая | Более сложная |
| Использование в Assert | Для проверки возвращаемых значений | Для проверки вызовов методов |
| Тип тестирования | Состояния (state-based) | Взаимодействия (interaction-based) |
Смешанные сценарии и современные подходы
На практике часто используются гибридные подходы:
- Spy (шпион) — частичный mock, который может вести себя как stub, но при этом отслеживает вызовы
- Fake (фейк) — упрощенная рабочая реализация зависимости (например, in-memory база данных)
В современных фреймворках границы иногда размыты, и один объект может выполнять обе роли, но концептуальное различие остается важным для написания чистых, понятных и целенаправленных тестов.
Вывод
Основное различие можно сформулировать так: stub помогает тесту запуститься, предоставляя необходимые данные, а mock проверяет, что тестируемый код правильно взаимодействует со своими зависимостями. Понимание этой разницы позволяет выбирать правильный инструмент для конкретной задачи тестирования, что ведет к более поддерживаемым и надежным тестам. Stub отвечает на вопрос "что", а mock — на вопрос "как".