Хуки
Что такое хуки в pytest?
подробнее
Общее понимание термина Хук
Хуки (hooks — «крючки») в программировании - это специальные точки расширения или функции, позволяющие вклиниться в выполнение чужого кода, фреймворка или системы, чтобы выполнить собственный код в определенный момент (до/после события).
Хук это не классический паттерн проектирования, а скорее технология или принцип проектирования, который делает приложения более модульными и эргономичными.
Хуки в pytest
Хуки — это специальные функции, с помощью которых можно настраивать поведение pytest без изменения самих тестов.
Хуки всегда начинаются наpytest_.
Pytest сам вызывает их в определённые моменты (старт сессии, парсинг CLI, коллекция тестов, параметризация, запуск, репортинг).
Где должны находиться функции-хуки?
подробнее
Объявление хуков производится в
conftest.py.
Примеры хуков
подробнее
-
pytest_collection_modifyitems(Динамическая настройка)
Срабатывает, когда pytest нашел все тесты, но еще не запустил их.
Позволяет автоматически добавлять маркеры (например,slowвсем тестам в папкеintegration) или исключать тесты на лету.
Пример:def pytest_collection_modifyitems(config, items): for item in items: if "integration" in str(item.fspath): item.add_marker(pytest.mark.slow) -
pytest_addoption(Свои флаги в CLI)
Позволяет добавить в команду запуска свои параметры (например,--envили--browser).
Пример:def pytest_addoption(parser): parser.addoption("--env", action="store", default="dev", help="Choose env: dev or prod") -
pytest_runtest_makereport(Слежка за результатом)
Срабатывает после каждого этапа теста (setup, call, teardown).
Пример:@pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield rep = outcome.get_result() if rep.when == "call" and rep.failed: print(f"Тест {item.nodeid} упал!")
Как параметризовать тест динамически?
подробнее
С помощью хука
pytest_generate_testsвconftest.py. Это позволяет генерировать параметры на лету, например, читая их из внешней базы или JSON-файла перед запуском.
Пример:
# conftest.py
def pytest_generate_tests(metafunc):
# Если тест принимает аргумент "db_engine"
if "db_engine" in metafunc.fixturenames:
# Допустим, мы берем список БД из конфига или БД
engines = ["postgres", "mysql", "sqlite"]
# Параметризуем тест динамически
metafunc.parametrize("db_engine", engines)
Как маркировать mark тест динамически?
подробнее
С помощью хука
pytest_collection_modifyitemsвconftest.py.
Этот хук вызывается, когда pytest уже нашел (собрал) все тесты, но еще не начал их выполнять. В этот момент мы можем пройтись по списку тестов (items) и добавить им маркеры.
Пример:
# conftest.py
def pytest_collection_modifyitems(config, items):
for item in items:
# 1. Маркировка по пути к файлу
if "integration" in str(item.fspath):
item.add_marker(pytest.mark.slow)
# 2. Маркировка по названию функции
if "delete" in item.name:
item.add_marker(pytest.mark.danger)
# 3. Маркировка на основе параметров (если тест параметризован)
if hasattr(item, "callspec") and item.callspec.params.get("user") == "admin":
item.add_marker(pytest.mark.priority)