Python: Selenium
Теория: Работа с ошибками
Работа с ошибками — Скриншот при падении теста
При автоматизации тестов важно не просто определить, что тест упал, но и понять, почему это произошло. Иногда текст ошибки Pytest или Selenium не даёт полного ответа. Визуальный снимок страницы помогает увидеть, что происходило в браузере в момент сбоя: не прогрузился элемент, исчез баннер, появилось модальное окно или всплыла неожиданная ошибка.
Сделать скриншот в Selenium очень просто — драйвер имеет встроенный метод save_screenshot(). Он сохраняет текущее состояние страницы в виде PNG-файла.
Если тест не смог найти элемент с ID wrong-id, Selenium выбросит исключение NoSuchElementException. Код внутри блока except поймает ошибку и сделает снимок экрана error.png в корне проекта. На изображении будет ровно то, что видел браузер в момент ошибки.
Скриншот при падении теста в Pytest
В реальных проектах ручное добавление try/except в каждый тест неудобно. Вместо этого используют фикстуру Pytest, которая автоматически делает скриншот при любой ошибке.
Теперь достаточно использовать фикстуру browser в любом тесте:
Если проверка не пройдёт, Pytest создаст папку screenshots/ и сохранит снимок страницы с именем test_example.png.
Зачем нужны скриншоты
Скриншот — это быстрый способ визуальной диагностики. По нему можно понять:
- элемент действительно отсутствует на странице;
- сайт не загрузился (пустой экран, ошибка 500 или 404);
- появилось всплывающее окно, перекрывающее кнопку;
- страница открылась не та (неправильный редирект).
В отличие от логов, скриншот показывает реальное состояние браузера, что особенно полезно при нестабильных интеграционных тестах.
Скриншоты и Allure
Если используется отчётность Allure, скриншоты можно прикреплять прямо в отчёт. Для этого в тест добавляют вызов allure.attach().
В отчёте Allure рядом с упавшим тестом появится вкладка с изображением страницы. Это позволяет анализировать ошибки прямо в интерфейсе отчёта.
Где хранить скриншоты
Хранить их можно в отдельной папке проекта, например screenshots/, или внутри отчётов Allure. Обычно к имени файла добавляют дату и время, чтобы не перезаписывать старые снимки:
Так можно отслеживать историю ошибок и видеть, когда началась деградация тестов.
Работа с ошибками — Логирование ошибок
Когда тест падает, скриншота часто недостаточно. Он показывает, что случилось на экране, но не объясняет, почему. Для этого в автотестах используется логирование — систематическая запись событий, действий и ошибок, которые происходят во время выполнения теста. Логи позволяют восстановить ход теста, понять, где он остановился, и увидеть причины сбоя без повторного запуска.
Что такое логирование в тестах
Логирование — это механизм, который фиксирует всё, что делает тест: какие страницы открываются, какие элементы найдены, какие данные введены, какие проверки прошли или упали. Каждая запись попадает в лог-файл вместе со временем, уровнем важности и сообщением.
Базовый инструмент для этого — стандартный модуль Python logging. Он встроен в язык и не требует установки дополнительных библиотек.
Простой пример логирования
После выполнения в папке проекта появится файл test_log.txt, где будет записан полный ход теста. Пример содержимого:
Если тест упадёт, в логах появится строка с уровнем ERROR и текстом исключения.
Уровни логов
Модуль logging поддерживает пять уровней сообщений:
DEBUG— подробные технические детали (редко выводятся в отчётах).INFO— основные шаги теста, которые позволяют понять, что происходит.WARNING— предупреждения, не критичные, но требующие внимания.ERROR— ошибки, из-за которых тест не может продолжиться.CRITICAL— фатальные сбои, после которых тест аварийно завершён.
Обычно в автотестах достаточно уровней INFO и ERROR. Первый фиксирует шаги теста, второй — причины падений.
Логирование в связке с Pytest
Pytest может автоматически перехватывать логи и добавлять их в отчёты. Если запустить тест с параметром -s, все логи выводятся прямо в консоль:
Если нужно писать логи в файл, добавляется конфигурация через фикстуру.
Теперь все тесты будут автоматически записывать логи в logs/tests.log.
Пример интеграции с Allure
Если используется Allure, можно прикреплять логи прямо к отчёту. Это особенно полезно для CI/CD, где нет доступа к файловой системе.
В отчёте появятся вкладки с текстом исключения и логами браузера. Это помогает понять, что именно пошло не так — баг на стороне фронтенда или ошибка в логике теста.
Логи браузера
Кроме логов теста, Selenium умеет получать сообщения из консоли браузера. Это позволяет фиксировать JavaScript-ошибки или проблемы с загрузкой.
Если в коде сайта возникла ошибка TypeError или 404 Not Found, она появится в этих логах.
Формирование структуры логов
В больших проектах логи делят на уровни и файлы:
tests.log— ход выполнения тестов;errors.log— только ошибки и исключения;debug.log— подробные внутренние данные, если нужно отладить.
Для этого можно создать несколько логгеров:
Теперь в errors.log будут сохраняться только записи уровня ERROR и выше.
Как использовать логи при анализе
- Проверить, в каком месте тест остановился.
- Найти последний успешный шаг.
- Посмотреть стек исключения в логах.
- Сравнить со скриншотом, чтобы понять, совпадает ли визуальная и фактическая ошибка.
Например, если в логах написано NoSuchElementException: Unable to locate element: [id="submit"], а на скриншоте видно всплывающее окно — причина ясна: модалка перекрыла кнопку.
Автоматическое создание логов в CI
При интеграции тестов в CI (например, GitHub Actions, GitLab CI или Jenkins) логи автоматически сохраняются как артефакты сборки. Это удобно: после запуска тестов можно скачать архив logs.zip и посмотреть результаты, не поднимая браузер вручную.
Что такое стек-трейс
Когда автотест падает, в терминале появляется длинная простыня текста.
Это и есть стек-трейс — последовательность вызовов функций, которые привели к ошибке. В нём указаны файлы, строки и имена функций. Нижние строки показывают самое глубокое место падения, а верхние — путь до него. Чтобы разобраться, что пошло не так, обычно хватает последних десяти строк: там виден ваш тест и вызовы Selenium, а не внутренние методы библиотек.
Форматы стека
Когда тест падает, Pytest выводит стек — список строк с файлами и функциями, которые вызывались до ошибки. Чтобы управлять длиной этого списка, у Pytest есть параметр --tb. Он означает traceback, то есть «обратная трассировка».
Если запустить тест с --tb=short, Pytest покажет только последние строки — то, где тест реально упал:
Пример вывода:
Такой формат подходит, если нужно просто увидеть, что не сработало.
Для подробного анализа используют --tb=long:
Теперь Pytest покажет весь путь — из библиотек Selenium, вашего теста и фикстур.
Видно, какая строка вызвала ошибку, какой локатор не найден и какой тип исключения сработал.
Есть и автоматический вариант — --tb=auto. Pytest сам решает, сколько строк показать: короткий стек для простых ошибок, длинный для сложных.
Сообщения в стеке
Чтобы сделать стек понятнее, можно добавить к assert собственный текст. Тогда Pytest выведет сообщение вместе с местом падения.
Пример:
Вывод будет таким:
Теперь сразу видно, чего не хватило.
Иногда нужно дополнить стек, если ошибка была перехвачена вручную. Тогда используют конструкцию raise ... from e. Она сохраняет оригинальное место падения и добавляет ваше пояснение:
Теперь в выводе появятся обе части: и место, где упал Selenium, и строка с пояснением.
Отладка через breakpoint
Во время выполнения теста иногда нужно увидеть, что именно происходит в браузере в конкретный момент. Для этого используют встроенную команду breakpoint(). Она ставит тест «на паузу» и открывает интерактивную консоль прямо внутри запущенного процесса.
Когда выполнение доходит до строки с breakpoint(), Pytest приостанавливает работу. В консоли можно вводить команды, проверять значения переменных, просматривать DOM и адрес страницы. Это удобно, если элемент не находится, а нужно понять — есть ли он в HTML, правильно ли открылся нужный URL, не перекрыт ли чем-то интерфейс.
Чтобы Pytest позволил работать с консолью, тест запускают так:
Флаг -s отключает подавление вывода и делает консоль «живой». Если хочется, чтобы отладка включалась автоматически при падении теста, добавляют флаг --pdb:
В этом режиме при ошибке сразу открывается консоль отладчика.
Пример теста с точкой остановки
Когда тест остановится, можно выполнять команды прямо в консоли. Полезно проверить:
Эти проверки помогают понять, загружена ли нужная страница и виден ли искомый элемент.
Сохранение стека и скриншота
Если ошибка повторяется, а вручную воспроизводить её неудобно, лучше сохранять артефакты автоматически. Для этого используют модуль traceback. Он записывает стек вызовов в лог, а Selenium делает скриншот страницы.
После падения появятся два файла:
-в логах будет текст ошибки с полным стеком,
-в папке screenshots — снимок страницы на момент сбоя.
Автоматическое сохранение при падении
Когда тестов становится десятки, добавлять в каждый блок try/except неудобно. Вместо этого всё можно сделать централизованно — через фикстуру в conftest.py. Фикстура создаёт браузер, передаёт его в тест, а после выполнения проверяет, упал ли сценарий. Если да — сохраняет скриншот и HTML страницы.
Теперь при любом падении Selenium автоматически сохраняет два файла — снимок экрана и HTML текущей страницы. HTML можно открыть в браузере и проверить, что элемент действительно отсутствовал или был скрыт под всплывающим окном. Это экономит время и помогает понять причину сбоя без повторного запуска.
Полезные флаги
Когда тестов много, удобно управлять прогоном с помощью флагов Pytest.
-x— прерывает выполнение на первом упавшем тесте. Это удобно при отладке, когда важно сразу остановиться и не ждать окончания всех прогонов.--maxfail=1делает то же, но мягче: фиксирует ограничение по количеству падений, после которых тестирование прекращается.--lf(last-failed) запускает только те тесты, которые упали в прошлый раз. Это ускоряет проверку после исправлений.-k "login and not smoke"позволяет запустить выборку тестов по ключевым словам. Например, прогнать все сценарии логина, кроме тех, что помечены как smoke.
Ожидания вместо ошибок
Одна из частых причин падений — элемент ещё не успел появиться на странице. Selenium пытается кликнуть, но DOM ещё не готов. Это вызывает ошибки NoSuchElementException или ElementClickInterceptedException. Решение — использовать явные ожидания.
В этом примере Selenium ждёт до 10 секунд, пока кнопка не станет кликабельной, и только потом кликает. Это безопаснее, чем просто find_element.
Проверка выборки
Иногда ошибка в стеке выглядит как внутренний сбой Selenium, но настоящая причина — пустая выборка. Проверить это можно просто:
Если список пуст, значит локатор неверный. Следует подобрать более стабильный селектор, например по id или уникальному классу. Чем точнее локатор, тем меньше случайных падений.
Логи браузера
Иногда тесты падают из-за ошибок в самом приложении, а не в автотестах. Через driver.get_log("browser") можно вывести сообщения из консоли браузера:
Если в выводе встречаются TypeError или 404, значит на странице есть JavaScript-ошибка или не загрузился нужный ресурс. Это повод завести баг на фронтенд, а не чинить тест.
Настройка Pytest
Чтобы отчёты были читаемыми, базовые параметры можно задать в файле pytest.ini:
Опция --tb=auto делает стек аккуратным: простые ошибки показываются коротко, сложные — с контекстом. log_cli включает вывод логов прямо в терминал во время прогона.
Отладка через PDB
Иногда проще всего поймать проблему вручную. Для этого используется встроенный отладчик Python — PDB. Его можно активировать флагом:
Когда тест падает, Pytest открывает консоль с интерактивным управлением. Основные команды:
n— перейти к следующей строке,s— шагнуть внутрь функции,c— продолжить выполнение,l— показать участок кода,p var— вывести значение переменной.
PDB помогает буквально «заглянуть» внутрь теста в момент сбоя. Можно проверить переменные, DOM и даже вручную повторить шаг, который не сработал. Такой подход ускоряет поиск причины и позволяет быстрее стабилизировать автотест.
Работа с ошибками — Повторное выполнение теста (pytest-rerunfailures)
Автотесты должны быть стабильными, но в реальности часть из них падает случайно. Это может быть проблема сети, задержка загрузки страницы, непредсказуемое поведение браузера или нестабильный элемент DOM. Такие падения называют флаки-тестами (flaky tests). Они не указывают на баг в продукте, но портят отчёт, создавая ложные ошибки.
Чтобы минимизировать влияние таких случайных сбоев, в Pytest используется плагин pytest-rerunfailures. Он автоматически повторяет тест, если тот упал, и считает его успешным, если повторное выполнение прошло без ошибок. Это не «маскирует» реальные дефекты, а помогает фильтровать нестабильность окружения.
Установка плагина
Плагин устанавливается одной командой:
Проверить, что он активен, можно через список установленных плагинов:
В выводе появится строка pytest_rerunfailures.
Простое использование
Чтобы запустить тест с повторным выполнением при падении, используется флаг --reruns.
Эта команда означает: если какой-то тест упал, Pytest перезапустит его до трёх раз. Если хотя бы один повтор пройдёт успешно, тест засчитывается как «пройденный после N повторов». Если упадёт все три раза — он считается действительно упавшим.
Можно добавить параметр --reruns-delay, чтобы сделать паузу между попытками. Это полезно, если проблема связана с медленной загрузкой страницы.
Здесь между каждой попыткой выполняется пауза в 2 секунды.
Пример с флаки-тестом
Иногда элемент не успевает появиться на странице, и тест падает с ошибкой NoSuchElementException.
Без ожидания тест может упасть. Но если его перезапустить, он пройдёт. Добавив --reruns 2, мы дадим системе шанс выполнить повтор и подтвердить, что ошибка не постоянная.
Настройка через декораторы
Если повтор нужно задать только для конкретного теста, можно использовать декоратор @pytest.mark.flaky(reruns=N, reruns_delay=D).
Теперь только этот тест будет перезапущен дважды, если упадёт. Остальные выполняются один раз.
Комбинация с Allure
Если проект использует Allure, повторные прогоны не теряются. В отчёте Allure каждый повтор фиксируется как отдельный шаг с пометкой flaky. Это позволяет видеть, сколько раз тест падал перед успешным выполнением.
Пример запуска:
В отчёте видно: «первая попытка — ошибка, вторая — успех». Это полезно для анализа нестабильных тестов и улучшения ожиданий.
Типичные причины флаки-поведения
Повторное выполнение помогает бороться с последствиями, но не с причиной. Часто тесты становятся нестабильными из-за:
- отсутствия явных ожиданий (элемент не успевает появиться);
- зависания браузера или JavaScript-ошибок;
- асинхронных операций на фронтенде;
- неочищенных данных предыдущего теста;
- слишком жёстких таймаутов.
Если один и тот же тест падает каждый раз — pytest-rerunfailures не поможет, потому что это реальный баг. Но если сбой редкий, повтор подтвердит стабильность сценария.
Интеграция с CI/CD
В CI-среде (например, Jenkins, GitLab, GitHub Actions) повторный запуск помогает сгладить случайные сетевые сбои. Обычно конфигурацию плагина выносят в pytest.ini:
Теперь все тесты при каждом запуске будут повторяться до двух раз при ошибке. Это избавляет от ложных падений при временных проблемах.


