При модульном тестировании зависимость заменили заглушкой: тесты проходят, хотя с реальной зависимостью формат данных несовместим. Какой риск тест-дизайна проявился?
Проявился риск чрезмерной изоляции тестируемого модуля: заглушка имитирует зависимость слишком упрощённо или неверно, поэтому тест подтверждает работу модуля только в искусственных условиях. Несовместимость с реальной зависимостью обнаружат лишь интеграционные, контрактные или сквозные проверки.
Модульное тестирование развивалось как способ быстро проверять небольшие части системы независимо от внешних сервисов, баз данных и сетевого окружения. Для этого применяют тестовые двойники: заглушки, стабы, моки и фейки.
Такой подход сокращает время выполнения тестов, делает ошибки локализованными и позволяет проверять модуль до готовности всех его зависимостей. Однако изоляция не должна создавать иллюзию, что взаимодействие с реальными компонентами уже проверено.
Заглушка может возвращать данные в удобном для теста формате, который отличается от фактического ответа зависимости. Она также может не воспроизводить обязательные поля, правила сериализации, ошибки, ограничения протокола или порядок взаимодействий.
В результате модульные тесты проходят, а в рабочей системе возникают ошибки разбора ответа, неверная обработка обязательного поля или несовместимость интерфейсов. Чем больше поведения реальной зависимости заменено предположениями теста, тем выше риск пропустить такую проблему.
Нужно разделять две проверки:
Заглушка должна отражать существенный контракт зависимости, а не только удобный для теста сценарий. Важно проверять структуру ответа, типы и обязательность полей, допустимые ошибки, коды результата и ключевые правила взаимодействия.
Полностью отказаться от тестовых двойников обычно невыгодно: реальные зависимости делают тесты медленнее, нестабильнее и сложнее в диагностике. Компромисс состоит в пирамиде проверок: основную массу составляют быстрые модульные тесты, а небольшой, но обязательный набор интеграционных или контрактных тестов проверяет границы компонентов.
Если интерфейс развивается независимо, полезны контрактные тесты. Они фиксируют ожидания потребителя и проверяют, что поставщик их выполняет. Но контрактные тесты не заменяют проверки бизнес-взаимодействия, производительности и отказоустойчивости в реальном окружении.
Сервис заказов тестировали с заглушкой сервиса доставки. Заглушка возвращала поле price числом, тогда как реальный сервис после изменения API начал возвращать его строкой. Модульные тесты продолжали проходить, но оформление заказа в рабочей среде завершалось ошибкой преобразования данных.
Рассматривались три варианта. Полностью заменить заглушку реальным сервисом означало бы повысить длительность и нестабильность каждого теста. Оставить только текущие модульные тесты было быстро, но риск несовместимости сохранялся. Добавить контрактную проверку и один интеграционный сценарий оказалось более сбалансированным решением.
В итоге заглушку синхронизировали с согласованным контрактом, а в CI добавили проверку фактического формата ответа поставщика. Модульные тесты сохранили скорость, а несовместимость стала обнаруживаться до публикации версии.
Нет, он доказывает корректность только относительно поведения, заданного тестом и его двойниками. Если заглушка неверно описывает реальную зависимость, тест может быть внутренне последовательным, но практически бесполезным для проверки интеграции.
Это увеличивает время выполнения, усложняет диагностику и делает результат зависимым от сети, данных и доступности внешних систем. Кроме того, интеграционный тест обычно хуже локализует причину сбоя. Поэтому нужны оба уровня: быстрые изолированные проверки и ограниченный набор проверок реального взаимодействия.
Когда её поведение поддерживают отдельно от реального контракта, описывают слишком упрощённо или проверяют только успешные ответы. Риск снижают централизованным описанием контракта, контрактными тестами, проверкой негативных сценариев и периодическим запуском интеграционных тестов с реальной зависимостью.