Custom markers и strict mode
Коллега написал @pytest.mark.slоw (с опечаткой). Тесты запустились, но маркер не сработал. Как защититься от таких ошибок?
Цель: Создать собственные маркеры и настроить strict mode для защиты от опечаток.
Вы точно готовы?
Убедитесь, что умеете:
# Использовать встроенные маркеры
@pytest.mark.skip
def test_skip():
pass
@pytest.mark.parametrize("value", [1, 2])
def test_param(value):
assert value > 0Если базовые маркеры непонятны — вернитесь к pytest-basics урок 5.
Проблема: неизвестные маркеры
Опечатка в маркере
# tests/test_api.py
@pytest.mark.slow # ✅ Правильно
def test_api_1():
pass
@pytest.mark.slоw # ❌ Опечатка (кириллическая 'о')
def test_api_2():
pass
@pytest.mark.sloww # ❌ Опечатка (две 'w')
def test_api_3():
passЗапуск:
pytest -m slowРезультат:
collected 3 items / 2 deselected / 1 selected
tests/test_api.py::test_api_1 PASSED
PytestUnknownMarkWarning: Unknown pytest.mark.slоw
PytestUnknownMarkWarning: Unknown pytest.mark.sloww❌ Тесты с опечатками не запустились! Но предупреждение легко пропустить.
Решение: strict markers
Регистрация маркеров в pytest.ini
# pytest.ini
[pytest]
markers =
slow: Медленные тесты (> 5 секунд)
integration: Integration тесты с внешними системами
smoke: Smoke тесты для быстрой проверки
unit: Unit тесты (изолированные)Включение strict mode
# pytest.ini
[pytest]
addopts =
--strict-markers # Ошибка на неизвестных маркерах
markers =
slow: Медленные тесты
integration: Integration тестыТеперь:
pytestРезультат:
ERROR: Unknown marker 'slоw' - is this a typo?✅ Опечатка превратилась в ошибку! Тесты не запустятся пока не исправим.
Альтернатива: CLI флаг
# Разово включить strict markers
pytest --strict-markers
# Разово отключить
pytest --strict-markers=FalseСоздание кастомных маркеров
Маркеры с документацией
# pytest.ini
[pytest]
markers =
# По скорости
slow: Медленные тесты (> 5 секунд). Используйте pytest -m "not slow" для быстрого запуска.
fast: Быстрые тесты (< 1 секунды)
# По типу
unit: Unit-тесты (изолированные, без внешних зависимостей)
integration: Integration-тесты (БД, API, файлы)
e2e: End-to-end тесты (полный цикл)
# По зависимостям
requires_db: Требует PostgreSQL
requires_redis: Требует Redis
requires_docker: Требует Docker
requires_network: Требует доступ в интернет
# По функциональности
auth: Тесты аутентификации/авторизации
payments: Тесты платежной системы
api: Тесты API endpoints
cli: Тесты CLI команд
# Специальные
smoke: Критичные тесты для smoke testing
regression: Regression тесты (проверка старых багов)
wip: Work In Progress (в разработке, могут падать)Просмотр маркеров:
pytest --markersРезультат:
@pytest.mark.slow: Медленные тесты (> 5 секунд). Используйте pytest -m "not slow"...
@pytest.mark.unit: Unit-тесты (изолированные, без внешних зависимостей)
...Использование маркеров
import pytest
@pytest.mark.slow
@pytest.mark.integration
@pytest.mark.requires_db
def test_complex_query():
"""Сложный запрос к БД"""
pass
@pytest.mark.unit
@pytest.mark.fast
def test_simple_calculation():
"""Простой расчёт"""
pass
@pytest.mark.smoke
@pytest.mark.api
def test_api_health():
"""Health check API"""
passЗапуск:
# Только быстрые unit тесты
pytest -m "unit and fast"
# Интеграционные, но не медленные
pytest -m "integration and not slow"
# Smoke тесты
pytest -m smokeМаркеры с аргументами
Skip с причиной
@pytest.mark.skip(reason="Waiting for API v2")
def test_api_v2():
pass
@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
def test_unix_specific():
passКастомные маркеры с аргументами
# Маркер с таймаутом
@pytest.mark.timeout(seconds=10)
def test_slow_operation():
pass
# Маркер с приоритетом
@pytest.mark.priority("high")
def test_critical_feature():
pass
# Маркер с багом
@pytest.mark.bug(issue="JIRA-123")
def test_regression():
passДоступ к аргументам:
# conftest.py
def pytest_collection_modifyitems(items):
"""Сортируем тесты по приоритету"""
def priority_key(item):
marker = item.get_closest_marker("priority")
if marker:
priorities = {"high": 1, "medium": 2, "low": 3}
return priorities.get(marker.args[0], 99)
return 99
items.sort(key=priority_key)Best practices (bonus)
1. Согласованность команды
# pytest.ini для всей команды
[pytest]
# Защита от опечаток
addopts = --strict-markers
markers =
# Используйте префиксы для группировки
type_unit: Unit тесты
type_integration: Integration тесты
type_e2e: E2E тесты
speed_slow: Медленные
speed_fast: Быстрые
dep_db: Требует БД
dep_redis: Требует Redis2. Минимальный набор маркеров
# ✅ ХОРОШО — минимально необходимые
markers =
slow: Медленные тесты
integration: Integration тесты
smoke: Smoke тесты
# ❌ ПЛОХО — слишком много
markers =
very_slow:
moderately_slow:
slightly_slow:
... # 50 маркеров3. Документация в README
## Маркеры тестов
- `@pytest.mark.slow` — медленные тесты (> 5с)
```bash
pytest -m "not slow" # Пропустить медленные
```@pytest.mark.smoke— критичные тестыpytest -m smoke # Быстрая проверка
Что вы изучили
- --strict-markers — защита от опечаток в маркерах
- Регистрация — markers в pytest.ini
- Документация — описание каждого маркера
- Аргументы — маркеры с параметрами
- Best practices — минимум маркеров, группировка, документация
Следующий урок
Отлично! Маркеры настроены и защищены от опечаток. Но что если нужно создать собственный pytest плагин для автоматизации команды?
Переходите к уроку 5: Создание pytest-плагинов
В следующем уроке вы узнаете:
- Hooks для расширения pytest
conftest.pyкак плагинpytest_configure,pytest_collection_modifyitems- Создание пакета плагина
Устранение неисправностей
Pytest не видит конфиг.
Проверьте:
- pytest.ini лежит в корне проекта
- Запускаете pytest из корня (или передайте -c path/to/pytest.ini)
- Нет опечатки в названии маркера в pytest.ini
Режим strict нужно включить.
# pytest.ini
[pytest]
addopts = --strict-markers
Либо запустите разово:
pytest --strict-markersCLI переопределит настройку.
pytest --strict-markers=falseИспользуйте вызов, а не присваивание.
# ✅ ПРАВИЛЬНО
@pytest.mark.timeout(10)
# ❌ НЕПРАВИЛЬНО
@pytest.mark.timeout = 10