Pytest на практике: тесты, фикстуры, параметры, марки, хуки
В прошлых статьях мы собрали окружение и разобрали основы Selenium: локаторы, действия и ожидания, а также закрепили идею Page Object Model (POM). Теперь добавим недостающий слой, который превращает набор Selenium-скриптов в управляемый тестовый проект: Pytest.
В этой статье разберём, как в UI-автотестах на Pytest + Selenium + POM правильно:
писать и организовывать тесты
управлять жизненным циклом браузера через фикстуры
запускать один и тот же тест с разными данными через параметризацию
группировать и выбирать тесты через марки
подключать хуки Pytest для практичных задач вроде скриншота при падении!Жизненный цикл фикстур и место conftest.py в проекте
Как Pytest устроен в контексте UI-автотестов
Для UI-автотестов Pytest чаще всего отвечает за:
обнаружение и запуск тестов
фикстуры для подготовки окружения (браузер, базовый URL, логирование)
параметризацию для разных данных и конфигураций
маркировки для выборочного запуска (smoke, regression)
хуки для реакций на события (например, падение теста)Selenium при этом остаётся внутри фикстур и Page Object классов, а тесты описывают сценарии.
Тесты: как Pytest находит и запускает проверки
Соглашения Pytest по автообнаружению:
файлы: test_.py или _test.py
функции: test_*
классы: Test* (обычно без __init__)Официальная документация: Pytest: Good Practices.
Минимальный тест UI-уровня выглядит так:
Практические правила для assert в UI:
проверяйте то, что действительно отражает состояние интерфейса
избегайте проверок “на глаз”, которые могут быть нестабильными (например, случайный порядок элементов)
для полей ввода читайте значение через get_attribute("value"), а не через textФикстуры: главный инструмент управления браузером
Фикстура в Pytest — это функция, которая подготавливает данные или состояние для теста и возвращает его.
В UI-тестах основная фикстура почти всегда driver.
Документация: Pytest: Fixtures.
Фикстура WebDriver с yield
Классический шаблон:
Как это работает:
код до yield выполняется до теста (подготовка)
значение после yield попадает в тест
код после yield выполняется после теста (очистка), даже если тест упалГде хранить фикстуры: conftest.py
conftest.py — специальный файл Pytest, который автоматически подхватывается в рамках директории.
Типичный подход для курса:
общие фикстуры хранить в корневом conftest.py
по мере роста проекта выносить части в отдельные модули, но экспортировать через conftest.pyВстроенная “подстановка” фикстур в тест
Pytest связывает фикстуры с тестом по имени аргумента:
Важно:
не нужно вызывать фикстуру как функцию
Pytest сам создаст объект driver и передаст его в тестScope фикстур: как часто создавать браузер
У фикстур есть параметр scope, который определяет, как часто фикстура создаётся заново.
Документация: Pytest: Fixture scopes.
| scope | Как часто создаётся | Когда применять в UI |
|---|---|---|
| function | на каждый тест | по умолчанию, самый безопасный вариант |
| class | на класс тестов | если в классе много сценариев и нужен общий логин |
| module | на файл | иногда для ускорения локального прогона |
| session | на весь запуск | осторожно, риск взаимного влияния тестов |
Пример scope="session" для base_url, потому что он не требует очистки браузера:
autouse: фикстура без явного указания
Если поставить autouse=True, фикстура будет применяться автоматически.
Полезно для вещей вроде логирования или очистки временных данных, но для браузера обычно не используют, чтобы зависимости теста были явными.
Параметризация: один тест, много наборов данных
Параметризация позволяет запустить один тест несколько раз с разными входными данными.
Документация: Pytest: Parametrize.
@pytest.mark.parametrize
Пример для проверки валидации логина:
Что важно в UI:
для каждого набора данных тест должен начинаться в одинаковом состоянии
фикстуры и подготовка должны гарантировать изоляциюids: читаемые имена прогонов
Чтобы в отчёте было видно, какой именно набор данных упал:
Марки: как группировать тесты и запускать только нужное
Марки — это метки, которыми вы помечаете тесты. По маркам удобно собирать разные “срезы”:
smoke для быстрых критичных сценариев
regression для полного набора
ui если в проекте появятся также API-тестыДокументация: Pytest: Mark.
Объявление маркеров в pytest.ini
Чтобы Pytest не предупреждал о неизвестных маркерах:
Использование маркеров в тестах
Выборочный запуск
Типичные команды:
Практичные хуки Pytest для UI-тестов
Хуки — это функции, которые Pytest вызывает в определённые моменты жизненного цикла запуска.
Документация: Pytest: Reference (Hooks).
В UI-автотестах хуки часто используют для:
скриншота при падении
логов браузера
добавления CLI-параметров вроде --base-url или --browserХук для скриншота при падении теста
Базовая идея:
Pytest сообщает, что тест упал
мы берём driver из фикстур теста
сохраняем скриншот в папку artifacts/Пример для conftest.py:
Пояснения к ключевым частям:
item.funcargs содержит аргументы теста, включая фикстуры
report.when == "call" означает, что падение произошло в теле теста, а не в setup или teardown
save_screenshot сохраняет изображение текущего состояния страницыДальше по курсу такой артефакт удобно прикручивать к отчётам, но даже без отчётов это сильно ускоряет расследование падений.
CLI-опции: --base-url и --browser
Чтобы не хардкодить URL и браузер в коде, можно добавить опции запуска.
Пример:
Использование:
На следующем шаге курса это удобно связать с фикстурой driver, чтобы переключать браузер без правок кода.
Рекомендованный минимум для UI-проекта на Pytest
Чтобы ваш проект оставался поддерживаемым, держитесь следующих правил:
фикстура driver создаёт и закрывает браузер, тесты не управляют жизненным циклом напрямую
ожидания и взаимодействия с UI живут в POM, а не в тестах
параметризация используется для данных, а не для копирования тестов
марки smoke и regression объявлены в pytest.ini и реально используются
хуки применяются точечно, когда дают практическую пользу, например скриншот при паденииЧто дальше
Теперь у нас есть полный “каркас” запуска UI-тестов:
Selenium даёт управление браузером
POM прячет локаторы, ожидания и действия в слой страниц
Pytest управляет жизненным циклом, данными, группировками и расширениямиВ следующих материалах курса мы будем расширять инфраструктуру проекта:
аккуратно конфигурировать WebDriver под разные браузеры и режимы запуска
улучшать BasePage и переиспользуемые ожидания
готовить проект к стабильному запуску в CI