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