Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Создание pytest-плагинов
pytest_plugins_basics

Создание pytest-плагинов

Hooks, conftest как плагин, pytest_configure, pytest_collection_modifyitems. Автоматизация для команды

Команде нужно автоматически пропускать тесты на Windows, логировать длительные тесты, сортировать по приоритету. Писать это в каждом conftest.py? Есть способ лучше!

Цель: Научиться создавать pytest плагины для автоматизации команды.

Вы точно готовы?

Убедитесь, что умеете:

# conftest.py и фикстуры @pytest.fixture def resource(): return Resource() # Маркеры @pytest.mark.slow def test_something(): pass

Если conftest.py или маркеры непонятны — вернитесь к предыдущим урокам.

Что такое pytest плагины

Плагины = hooks + фикстуры

Плагин — это код который расширяет pytest через hooks.

Hook — функция которая вызывается pytest в определённые моменты:

pytest start
    ↓
pytest_configure()      # Конфигурация
    ↓
pytest_collection()     # Сбор тестов
    ↓
pytest_collection_modifyitems()  # Модификация списка тестов
    ↓
pytest_runtest_setup()  # Setup перед тестом
    ↓
test execution          # Тест
    ↓
pytest_runtest_teardown()  # Teardown после теста
    ↓
pytest_sessionfinish()  # Завершение сессии

conftest.py как плагин

conftest.py = локальный плагин

Любой conftest.py — это плагин! Можно определять hooks прямо в нём.

Hook: pytest_configure

# conftest.py def pytest_configure(config): """Вызывается при старте pytest""" print("\n🚀 Pytest starting...") # Добавляем кастомный атрибут config.custom_value = "Hello from plugin" # Регистрируем маркеры программно config.addinivalue_line( "markers", "custom: Custom marker added by plugin" )

Запуск:

pytest

Результат:

🚀 Pytest starting...
========================= test session starts ==========================

Hook: pytest_collection_modifyitems

# conftest.py def pytest_collection_modifyitems(config, items): """Модифицирует список собранных тестов""" print(f"\n📋 Collected {len(items)} tests") # Сортируем тесты по имени items.sort(key=lambda item: item.name) # Добавляем маркер ко всем тестам for item in items: item.add_marker("analyzed")

Практические примеры

Пример 1: Автоматический skip на Windows

# conftest.py import sys import pytest def pytest_collection_modifyitems(items): """Пропускаем unix_only тесты на Windows""" if sys.platform == "win32": skip_windows = pytest.mark.skip(reason="Unix only") for item in items: if "unix_only" in item.keywords: item.add_marker(skip_windows)

Использование:

# tests/test_unix.py @pytest.mark.unix_only def test_unix_feature(): """Автоматически пропустится на Windows""" pass

Пример 2: Логирование медленных тестов

# conftest.py import pytest import time @pytest.hookimpl(hookwrapper=True) def pytest_runtest_call(item): """Замеряем время выполнения теста""" start = time.time() yield duration = time.time() - start if duration > 1.0: print(f"\n⚠️ Slow test: {item.name} took {duration:.2f}s")

Пример 3: Сортировка по приоритету

# conftest.py def pytest_collection_modifyitems(items): """Сортируем тесты по приоритету""" priorities = {"critical": 0, "high": 1, "medium": 2, "low": 3} def priority_key(item): marker = item.get_closest_marker("priority") if marker and marker.args: return priorities.get(marker.args[0], 99) return 99 items.sort(key=priority_key)

Использование:

@pytest.mark.priority("critical") def test_critical_feature(): pass @pytest.mark.priority("low") def test_nice_to_have(): pass

Пример 4: Автоматические маркеры по пути

# conftest.py def pytest_collection_modifyitems(items): """Добавляем маркеры по пути к файлу""" for item in items: # Если тест в tests/integration/ if "integration" in str(item.fspath): item.add_marker(pytest.mark.integration) # Если тест в tests/unit/ if "unit" in str(item.fspath): item.add_marker(pytest.mark.unit)

Пример 5: Кастомный reporter

# conftest.py def pytest_runtest_logreport(report): """Вызывается после каждого теста""" if report.when == "call": if report.passed: print(f"✅ {report.nodeid}") elif report.failed: print(f"❌ {report.nodeid}")

Создание пакета плагина

Структура плагина

my-pytest-plugin/
├── pytest_my_plugin/
│   ├── __init__.py
│   └── plugin.py
├── tests/
│   └── test_plugin.py
├── pyproject.toml
└── README.md

1. Код плагина

# pytest_my_plugin/plugin.py import pytest def pytest_configure(config): """Регистрируем кастомные маркеры""" config.addinivalue_line( "markers", "team: Tests for team feature" ) def pytest_collection_modifyitems(items): """Сортируем тесты по имени""" items.sort(key=lambda x: x.name) @pytest.fixture def team_data(): """Фикстура от плагина""" return {"name": "TeamA", "members": 5}
# pytest_my_plugin/__init__.py from .plugin import *

2. pyproject.toml

# pyproject.toml [build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "pytest-my-plugin" version = "0.1.0" description = "My awesome pytest plugin" authors = [{name = "Your Name", email = "you@example.com"}] requires-python = ">=3.8" dependencies = [ "pytest>=7.0.0", ] # Регистрируем плагин в pytest [project.entry-points.pytest11] my_plugin = "pytest_my_plugin.plugin"

Ключевая часть: [project.entry-points.pytest11] регистрирует плагин!

3. Тесты для плагина

# tests/test_plugin.py def test_team_fixture(team_data): """Тестируем фикстуру плагина""" assert team_data["name"] == "TeamA" assert team_data["members"] == 5 @pytest.mark.team def test_team_marker(): """Тестируем маркер плагина""" pass

4. Установка и использование

# Установка в editable режиме pip install -e . # Проверка что плагин установлен pytest --version # pytest 7.x.x # plugins: my-plugin-0.1.0 # Использование pytest tests/

✅ Плагин работает автоматически!

Популярные hooks (bonus)

pytest_addoption — CLI опции

def pytest_addoption(parser): """Добавляем кастомную CLI опцию""" parser.addoption( "--env", action="store", default="test", help="Environment: test, staging, prod" ) @pytest.fixture def env(request): """Фикстура для доступа к --env""" return request.config.getoption("--env")

Использование:

pytest --env=staging
def test_api(env): assert env == "staging"

pytest_generate_tests — динамическая параметризация

def pytest_generate_tests(metafunc): """Динамически параметризуем тесты""" if "browser" in metafunc.fixturenames: browsers = metafunc.config.getoption("--browsers", "chrome").split(",") metafunc.parametrize("browser", browsers)

pytest_sessionfinish — финальные действия

def pytest_sessionfinish(session, exitstatus): """Вызывается в конце сессии""" print(f"\n✅ Tests finished with status: {exitstatus}") print(f"Total tests: {len(session.items)}")

Что вы изучили

  • Hooks system — расширение pytest через hooks
  • conftest.py — локальный плагин для проекта
  • pytest_configure — настройка при старте
  • pytest_collection_modifyitems — модификация тестов
  • Создание пакета — плагин как Python package
  • entry_points — регистрация плагина в pytest

Проверьте свои знания

Вопросы ещё не добавлены

Вопросы для этой подтемы ещё не добавлены.

Далее: Coverage thresholds и enforcement