API-тесты тоже флейкают 😭
В автоматизации есть иерархия стабильности. Считается, что UI-тесты (веб и мобилки) - это всегда зона риска, а API-тесты - это идеал стойкости: быстрые, надежные и стабильные. 🏔
Так - в теории, а на практике API-тесты часто бывают капризными. Когда они начинают флейкать (то падать, то проходить без правок кода), это раздражает даже больше, чем упавший Selenium. От бэкенда мы ждем непредсказуемости в последнюю очередь.
Почему API-тест перестает быть надежным? 📉
Если кажется, что API-автоматизация - это просто assert response.status_code == 200, то в реальности, она посложнее. Вот что вас ждет:
➖Гонка со сторонними сервисами 🏃♂️: Ваш тест дергает эндпоинт, который идет в сторонний платежный шлюз или сервис рассылок. Сторонний сервис задержался на пару секунд - и ваш тест падает по таймауту.
➖Консистентность данных ⏱️: Вы создаете юзера в одном микросервисе, а проверить его пытаетесь в другом. Данные еще не успели синхронизироваться в БД или Elastic, и ваш ассерт смотрит на пустой ответ.
➖Загрязнение окружения 🧹: Тест А создал данные и не удалил их. Теперь тест Б падает, потому что "такой email уже существует". В итоге у вас не изоляция, а "коммунальная квартира" с общими зависимостями.
➖Хрупкие тестовые данные: Кто-то вручную изменил конфиг в БД или удалил того самого юзера, на котором держалось пол-пайплайна. 🤯
Как лечить нестабильность? 🛠
Игнорировать флейки нельзя - они подрывают доверие ко всей автоматизации. Если отчеты краснеют без причины, пора внедрять правильные паттерны. И с хрупкими данными понятно - используй стабильные, выверенные. Всегда чисти после теста - официально - "возвращай систему в то же состояние, которое было до теста". Но что делать с задержками синхронизации, лагами. Ведь time.sleep() - это фу-фу-фу
В Python один из лучших помощников - библиотека tenacity. Она позволяет настроить умные ретраи (повторные попытки). Вместо того чтобы падать сразу, тест подождет и попробует еще раз, это часто решает проблемы с долгой синхронизацией.
Что стоит внедрить:
➖tenacity.retry - для повторов с задержкой ⏳
➖Умные ожидания - вместо time.sleep() используем циклы с проверкой условия, пока данные не появятся в базе или где вы их там ждете
➖Pytest-rerunfailures - это на крайняк для перезапуска упавшего теста целиком, если вылечить сложно, а перепрогон в большинстве случаев помогает
Вот простенький пример, чтобы можно было сразу попробовать. Страница https://analytics-api.com/users/42 вернет 404 и степ повторится 3 раза - увидите это по повторяющемуся "Валидирую статус ответа"
import requests
from tenacity import retry, stop_after_attempt, wait_fixed
# Пробуем 3 раза с паузой в 2 секунды
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2))
def step_wait_for_data(user_id):
response = requests.get(f"https://analytics-api.com/users/{user_id}")
# Если статус не 200, ассерт падает, вызывая AssertionError.
# Tenacity ловит это исключение и запускает повтор.
print("Валидирую статус ответа")
assert response.status_code == 200
return response.json()
def test_data():
# Тест будет идти до 6 секунд, если данные появятся не сразу
user_data = step_wait_for_data(42)
assert user_data['name'] == "Ivan"
Но! Осторожно с ретраями, а тем более реранами. ⚠️
В приложении может реально быть проблема. Например, эндпоинт отрабатывает всегда только с третьего раза. Сначала разберитесь с проблемой, сходите с ней к разработчикам или другим ответственным. И только если вам сказали (или вы знаете из опыта), что такое поведение почему-то ок, то retry - то, что вам надо
Стабильность - это не удача, а результат выбора правильных инструментов и архитектуры. 👨💻
Если вы всё еще лечите флейки через time.sleep(5), моргните два раза в комментариях 👇
Мы вас не осудим (почти)