Маркеры: запускаем нужные тесты
У вас 100 тестов. 90 быстрых (< 1 сек) и 10 медленных (> 10 сек). При разработке хочется запускать только быстрые. Как?
Цель: Научиться группировать тесты с помощью маркеров и запускать только нужные подмножества.
Вы точно готовы?
Убедитесь, что умеете:
# Запустить все тесты
pytest
# Запустить один файл
pytest tests/test_user.pyЕсли базовые команды pytest непонятны — вернитесь к урокам 0-4.
Проблема: все тесты запускаются каждый раз
Реальный сценарий:
# При разработке запускаем pytest
pytest
# Запускается 100 тестов, из них:
# - 90 быстрых (unit) — 10 секунд total
# - 10 медленных (integration с БД) — 50 секунд total
# Итого: 60 секунд!Проблема: Ждать минуту после каждого изменения — слишком долго.
@pytest.mark для группировки
Базовый маркер: @pytest.mark.slow
# tests/test_user.py
def test_user_creation():
"""Быстрый unit-тест"""
user = User("Alice", 25)
assert user.name == "Alice"
# Выполняется < 1 секунды
import pytest
@pytest.mark.slow
def test_user_save_to_database():
"""Медленный integration-тест с БД"""
user = User("Alice", 25)
user.save() # Запись в PostgreSQL
# Проверяем что сохранилось
loaded = User.load_from_db("Alice")
assert loaded.age == 25
# Выполняется ~5 секундЗапуск тестов с маркерами
Запустить ТОЛЬКО медленные тесты:
pytest -m slowРезультат:
======================== test session starts ============================
collected 2 items / 1 deselected / 1 selected
tests/test_user.py::test_user_save_to_database PASSED [100%]
================= 1 passed, 1 deselected in 5.01s ====================✅ Запустился только тест с @pytest.mark.slow!
Запустить ВСЁ КРОМЕ медленных тестов:
pytest -m "not slow"Результат:
======================== test session starts ============================
collected 2 items / 1 deselected / 1 selected
tests/test_user.py::test_user_creation PASSED [100%]
================= 1 passed, 1 deselected in 0.01s ====================✅ Медленный тест пропущен!
Регистрация маркеров в pytest.ini
Проблема: предупреждения о неизвестных маркерах
При запуске pytest:
PytestUnknownMarkWarning: Unknown pytest.mark.slowПричина: pytest не знает о маркере slow.
Решение: зарегистрировать в pytest.ini
# pytest.ini (в корне проекта)
[pytest]
markers =
slow: Медленные тесты (> 5 секунд)
integration: Integration-тесты с внешними системами
unit: Unit-тесты (изолированные)После этого предупреждения исчезнут!
Посмотреть все зарегистрированные маркеры
pytest --markersРезультат:
@pytest.mark.slow: Медленные тесты (> 5 секунд)
@pytest.mark.integration: Integration-тесты с внешними системами
@pytest.mark.unit: Unit-тесты (изолированные)
...Практические примеры группировки
По скорости выполнения
import pytest
# Быстрый тест (без маркера или @pytest.mark.unit)
def test_add_numbers():
"""Unit-тест, < 1 сек"""
assert add(2, 3) == 5
@pytest.mark.slow
def test_batch_import():
"""Импорт 10000 записей в БД"""
import_users_from_csv("large_file.csv")
assert User.count() == 10000
# Выполняется ~20 секундКоманды:
# Локально: только быстрые
pytest -m "not slow"
# CI: все тесты
pytestПо типу тестов
@pytest.mark.unit
def test_validate_email():
"""Unit-тест: изолированная логика"""
assert validate_email("test@example.com") == True
@pytest.mark.integration
def test_send_email_via_smtp():
"""Integration: реальный SMTP-сервер"""
send_email("test@example.com", "Subject", "Body")
# Требует доступа к SMTPКоманды:
# Только unit-тесты
pytest -m unit
# Только integration-тесты
pytest -m integrationПо функциональности
@pytest.mark.auth
def test_login_success():
"""Тесты аутентификации"""
pass
@pytest.mark.payments
def test_process_payment():
"""Тесты платежей"""
pass
@pytest.mark.api
def test_api_endpoint():
"""Тесты API"""
passКоманды:
# Только тесты аутентификации
pytest -m auth
# Платежи И API
pytest -m "payments or api"Комбинирование маркеров
Несколько маркеров на одном тесте
@pytest.mark.integration
@pytest.mark.slow
@pytest.mark.requires_db
def test_complex_query():
"""Сложный запрос к БД"""
passЛогические операторы
# Только integration, но НЕ slow
pytest -m "integration and not slow"
# Либо auth, либо payments
pytest -m "auth or payments"
# integration, но НЕ requires_db
pytest -m "integration and not requires_db"Практический workflow (реальный проект)
pytest.ini с полным набором маркеров
[pytest]
markers =
# По скорости
slow: Медленные тесты (> 5 секунд)
fast: Быстрые тесты (< 1 секунды)
# По типу
unit: Unit-тесты (изолированные)
integration: Integration-тесты с внешними системами
e2e: End-to-end тесты (полный цикл)
# По зависимостям
requires_db: Требует PostgreSQL
requires_redis: Требует Redis
requires_api: Требует внешний API
# По функциональности
auth: Тесты аутентификации
payments: Тесты платежей
api: Тесты API endpointsТипичные команды
# Разработка: быстрые unit-тесты
pytest -m "unit and not slow"
# Перед commit: unit + integration (без slow)
pytest -m "not slow and not e2e"
# CI: все тесты
pytest
# Дебаг конкретной фичи: только auth
pytest -m auth
# Pre-deploy: только критичные
pytest -m "payments or auth"Пример реального теста
import pytest
@pytest.mark.integration
@pytest.mark.slow
@pytest.mark.requires_db
@pytest.mark.payments
def test_stripe_payment_with_refund():
"""
Полный цикл платежа:
1. Создание charge в Stripe
2. Сохранение в БД
3. Рефанд
4. Проверка статуса в БД
"""
# Arrange
payment = create_payment(amount=100, currency="usd")
# Act
charge = process_stripe_charge(payment)
save_to_db(charge)
refund = refund_payment(charge.id)
# Assert
assert refund.status == "succeeded"
assert Payment.get(charge.id).status == "refunded"Запустить только этот тест:
pytest -m "payments and integration"Что вы изучили
- @pytest.mark.slow — маркировка медленных тестов
- pytest -m — выборочный запуск
- pytest.ini markers — регистрация маркеров
- Логические операторы —
and,or,not - Группировка тестов — по скорости, типу, функциональности
- Real-world workflow — разные команды для dev/CI
Следующий урок
Поздравляю! Вы изучили 6 из 8 основных уроков pytest-basics!
В следующем уроке вы узнаете про фикстуры — один из самых мощных инструментов pytest. Больше не придётся копировать setup-код в каждом тесте!
Переходите к уроку 6: Fixtures: создаём данные один раз
В следующем уроке вы узнаете:
@pytest.fixtureдля переиспользования setup- Фикстуры с yield для teardown
- Scope фикстур (function, class, module)
- Как избавиться от дублирования в тестах
Устранение неисправностей
Добавьте маркер в pytest.ini в секцию [pytest]
Проверьте:
- Откройте pytest.ini и перечислите маркеры в блоке markers
- Сохраните описание для каждого маркера (slow, integration и т.д.)
Проверьте написание и применение маркера
Проверьте:
- Используйте нижний регистр:
@pytest.mark.slow - Декоратор стоит над тестом
- Запускаете pytest из корня, чтобы pytest.ini подхватился
Используйте отрицание: pytest -m "not slow"
Проверьте:
- Убедитесь, что медленные тесты действительно помечены slow
- Для сложных условий комбинируйте not/and/or
Комбинируйте маркеры логическим AND
Проверьте:
- Пример:
pytest -m "integration and payments" - Убедитесь, что тест помечен обоими маркерами