Skip to content
IRC-CodingIRC-Coding
Test DoublesMockStubFakeDummySpyUnit Tests

Mock, Stub, Fake и Test Doubles: объекты-заменители

Изучите различия между Mock, Stub, Fake, Dummy и Spy. Test Doubles упрощают изолированное тестирование и повышают его скорость.

S

schutzgeist

4 min read
Mock, Stub, Fake и Test Doubles: объекты-заменители

Mock, Stub, Fake и тестовые двойники

Тестовые двойники — это объекты-заменители для реальных зависимостей в тестах. Они помогают изолировать компоненты при тестировании, отключать внешние системы и делать тесты детерминированными. Если разобраться в различиях между Mock, Stub, Fake, Dummy и Spy, получатся более точные и поддерживаемые тесты.

Коротко

  • Тестовые двойники заменяют реальные зависимости в тестах.
  • Dummy, Stub, Fake, Spy и Mock отличаются поведением и назначением.
  • Mocks проверяют взаимодействия, Stubs предоставляют фиксированные ответы, Fakes содержат упрощённую логику.
  • Слишком много Mocks могут сделать тесты хрупкими.

Определение

Термин Test Double взят из кинематографа — как актёра заменяет его дубль. Тестовый двойник точно так же подменяет реальную зависимость в тесте. Цель состоит в том, чтобы изолировать тестируемый код от внешнего мира, оценивая только его поведение.

Пять типов тестовых двойников

Dummy

Dummy — это объект, который передаётся в параметрах, но никогда не используется. Он нужен только для соблюдения сигнатуры метода.

Stub

Stub возвращает предопределённые ответы на вызовы. Он заменяет реальную зависимость фиксированным результатом, не содержа собственной логики.

Fake

Fake содержит упрощённую, но работающую реализацию. Типичный пример — In-Memory-репозиторий вместо настоящей базы данных.

Spy

Spy записывает вызовы, чтобы проверить их позже. По сути это ручная версия Mock.

Mock

Mock — это объект, в котором ожидаемые взаимодействия определены до теста. После теста проверяется, произошли ли эти вызовы на самом деле.

Практический пример: обработка заказов с тестовыми двойниками

from unittest.mock import Mock

class OrderService:
    def __init__(self, payment_gateway, inventory_repository):
        self.payment_gateway = payment_gateway
        self.inventory_repository = inventory_repository

    def process_order(self, order):
        available = self.inventory_repository.is_available(order.product_id)
        if not available:
            return {"status": "failed", "reason": "out_of_stock"}
        payment_result = self.payment_gateway.charge(order.amount)
        if payment_result.success:
            return {"status": "success"}
        return {"status": "failed", "reason": payment_result.error}

class PaymentResult:
    def __init__(self, success, error=None):
        self.success = success
        self.error = error

def test_order_success():
    inventory = Mock()
    inventory.is_available.return_value = True

    payment = Mock()
    payment.charge.return_value = PaymentResult(success=True)

    service = OrderService(payment, inventory)
    result = service.process_order(Mock(product_id=1, amount=99.99))

    assert result["status"] == "success"
    payment.charge.assert_called_once_with(99.99)

Преимущества и недостатки

Преимущества

  • Изоляция: внешние системы и медленные зависимости отключаются.
  • Скорость: тесты выполняются без реальных баз данных и сетевых запросов.
  • Детерминизм: фиксированные возвращаемые значения делают тесты предсказуемыми.
  • Фокус: проверяется только поведение конкретного компонента.

Недостатки

  • Ложная уверенность: Mocks могут дать неправильное представление о реальности.
  • Затраты на поддержку: тесно связанные Mocks ломаются при рефакторинге.
  • Усложнение: слишком много двойников скрывают реальное поведение.
  • Кривая обучения: тонкие различия между Mock и Stub часто неправильно понимают.

Контрольные пункты

  • Определение и назначение тестовых двойников.
  • Различия между Dummy, Stub, Fake, Spy и Mock.
  • Когда использовать каждый тип двойника.
  • Преимущества и риски Mocks.
  • Связь с пирамидой тестирования и изолированным тестированием.

Типичные вопросы (с кратким ответом)

  1. Что такое тестовый двойник? Объект-заменитель для реальной зависимости в тесте.

  2. В чём разница между Mock и Stub? Stub возвращает фиксированные ответы, Mock проверяет взаимодействия.

  3. Что такое Fake? Заменитель с упрощённой, но функциональной логикой.

  4. Когда использовать Dummy? Когда объект нужно передать как параметр, но он не используется в тесте.

  5. Какой недостаток у Mocks? Они могут слишком привязать тест к реализации и сломаться при изменениях кода.

Основные источники

  1. https://martinfowler.com/bliki/TestDouble.html
  2. https://xunitpatterns.com/Test%20Double.html
  3. https://en.wikipedia.org/wiki/Test_double

Часто задаваемые вопросы

В чём основная причина использования тестовых двойников?

Тестовые двойники заменяют реальные зависимости, позволяя изолировать, быстро и детерминированно тестировать компонент.

Mock и Stub это одно и то же?

Нет. Stub возвращает предопределённые ответы, а Mock определяет и позже проверяет взаимодействия.

Какой типичный пример Fake?

In-Memory-репозиторий, который заменяет реальную базу данных, но по-прежнему поддерживает основные операции сохранения и запроса.

Когда Mock использовать не стоит?

Избегайте Mocks, когда реальное взаимодействие с зависимостью — это ключевое поведение, например при сложных запросах к базе.

Что такое Spy?

Spy записывает вызовы для проверки в тесте. Это ручная альтернатива Mock.

Что такое Dummy?

Dummy — это объект, который передаётся как параметр, но не играет роли в самом тесте.

Могут ли тестовые двойники скрывать ошибки?

Да, если они слишком упрощают или делают неверные предположения о поведении реальной зависимости.

Сколько максимум Mocks должно быть в одном тесте?

Строгих правил нет, но тест с несколькими Mocks становится сложным и хрупким. Лучше иметь чёткую единицу и немного хорошо обоснованных двойников.

Что такое Interaction Testing?

Interaction Testing проверяет, вызывает ли компонент свои зависимости ожидаемым образом. Для этого используются Mocks.

Что такое State Testing?

State Testing проверяет результат или состояние после действия, без детального наблюдения за взаимодействиями.

Нужно ли мокировать внешние API?

В unit-тестах да, чтобы обеспечить изоляцию и скорость. Для интеграционных тестов лучше использовать реальные или хотя бы близкие к реальности интерфейсы.

В чём преимущество Fake перед Mock?

Fake содержит реальную, хотя и упрощённую логику и дарит более реалистичное представление о зависимости, чем жёсткие Mocks.

Какие фреймворки предоставляют тестовые двойники?

Популярные фреймворки: Mockito для Java, unittest.mock для Python, Moq для C#, NSubstitute для .NET и jest.fn() для JavaScript.

Что означает Over-Mocking?

Over-Mocking означает, что тест мокирует слишком много зависимостей. Это делает тест хрупким и малоинформативным.

Как тестовые двойники помогают пирамиде тестирования?

Они позволяют создавать большое количество быстрых, изолированных unit-тестов, формируя широкую основу пирамиды.

Дальше на пути Software Testing

Следующая статья на пути Software Testing охватывает Test Driven Development: Red, Green, Refactor — основы TDD с циклом Red-Green-Refactor.

Назад к блогу
Share:

Nächster Artikel in Качество программного обеспечения

Weiterlesen
Mutation Testing: Насколько хороши твои тесты?

Похожие статьи