Добавить в корзинуПозвонить
Найти в Дзене

Глубокое погружение в pytest-testmon: Умный отбор тестов для Python-проектов

pytest-testmon — это интеллектуальный плагин для pytest, который автоматически определяет, какие тесты нужно запустить после изменений кода. Вместо полного прогона всех тестов каждый раз (что может занимать часы в крупных проектах), testmon использует анализ зависимостей кода, чтобы выполнить только релевантные тесты, экономя до 90% времени. Проблема, которую решает testmon: В проектах с 1000+ тестами их полный запуск становится узким местом в разработке. Классические методы вроде pytest -k или ручного указания файлов неэффективны и подвержены ошибкам. Testmon автоматизирует этот процесс через отслеживание связей между кодовой базой и тестами. 1. Сбор метрик покрытия: - При первом запуске pytest --testmon инструмент выполняет ВСЕ тесты, собирая данные о том, какие строки кода были затронуты каждым тестом. - Результаты сохраняются в скрытом файле .testmondata (SQLite-база). 2. Анализ изменений: - При последующих запусках testmon сравнивает текущее состояние кода с предыдущей версией (че
Оглавление

pytest-testmon — это интеллектуальный плагин для pytest, который автоматически определяет, какие тесты нужно запустить после изменений кода. Вместо полного прогона всех тестов каждый раз (что может занимать часы в крупных проектах), testmon использует анализ зависимостей кода, чтобы выполнить только релевантные тесты, экономя до 90% времени.

Проблема, которую решает testmon:

В проектах с 1000+ тестами их полный запуск становится узким местом в разработке. Классические методы вроде pytest -k или ручного указания файлов неэффективны и подвержены ошибкам. Testmon автоматизирует этот процесс через отслеживание связей между кодовой базой и тестами.

Как работает testmon: Магия под капотом

1. Сбор метрик покрытия:

- При первом запуске pytest --testmon инструмент выполняет ВСЕ тесты, собирая данные о том, какие строки кода были затронуты каждым тестом.

- Результаты сохраняются в скрытом файле .testmondata (SQLite-база).

2. Анализ изменений:

- При последующих запусках testmon сравнивает текущее состояние кода с предыдущей версией (через контроль версий).

- Определяет все изменённые файлы, функции и классы.

3. Интеллектуальный отбор тестов:

- С помощью собранных данных testmon вычисляет, какие тесты затрагивают изменённые участки кода.

- Запускаются ТОЛЬКО эти тесты + тесты, помеченные как "ненадёжные" (flaky).

4. Кеширование и инкрементальность:

- Результаты прогонов кешируются. Если код не менялся, тесты не запускаются повторно.

- Поддерживается инкрементальное добавление новых тестов.

Ключевые преимущества

1. Экономия времени:

# До
$ pytest # 15 минут
# После
$ pytest --testmon # 47 секунд (если изменён 1 файл)

2. Автоматизация рутины:

- Больше не нужно гадать, какие тесты запустить после git pull или правки кода.

3. Совместимость с CI/CD:

- Уменьшение времени сборки на 60-80% в пайплайнах.

- Пример для GitHub Actions:

steps:
..- name: Run impacted tests
....run: pytest --testmon

4. Гибкая конфигурация:

- Исключение файлов через .testmonignore (аналог .gitignore):

legacy/*
generated_code.py

Установка и настройка

1. Установка:

pip install pytest-testmon

2. Базовое использование:

# Первый запуск (собирает данные)
pytest --testmon
# Последующие запуски (умный отбор)
pytest --testmon

3. Интеграция с pytest.ini:

[pytest]
addopts = --testmon

4. Игнорирование файлов:

Создайте .testmonignore в корне проекта:

/migrations/
/tests/data/*
*.ipynb

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

Сценарий 1: Изменение в бизнес-логике

Допустим, вы исправили функцию calculate_tax() в finance/utils.py. Testmon:

- Определит все тесты, покрывающие этот файл.

- Запустит только их, проигнорировав тесты для UI или API.

Сценарий 2: Рефакторинг без изменений поведения

Если правки не затронули исполняемый код (комментарии, форматирование), testmon пропустит запуск тестов.

Сценарий 3: Добавление нового теста

Новый тест будет запущен единожды, а его связи с кодом добавятся в .testmondata.

Ограничения и подводные камни

1. Динамический импорт:

Если модули загружаются через importlib или exec, testmon может не отследить зависимости.

2. Изменение поведения без изменения кода:

- Внешние API, обновление БД. Решение: ручной запуск с флагом --no-testmon.

3. Ограниченная поддержка ООП:

- Наследование и полиморфизм могут требовать дополнительных тестов. Рекомендация: помечать базовые классы как "опасные" через декоратор:

@pytest.mark.testmon(always_run=True)
class TestBaseAPI:
...

4. Конфликты с плагинами:

- Несовместимость с некоторыми плагинами (например, `pytest-randomly`). Решение: отключать конфликтующие инструменты при использовании testmon.

Интеграция с другими инструментами

1. pytest-cov (покрытие кода):

pytest --testmon --cov

- Coverage-отчёт строится ТОЛЬКО для запущенных тестов. Для полной статистики раз в сутки запускайте полный тестовый прогон.

2. pytest-xdist (параллельный запуск):

pytest --testmon -n auto

- Testmon автоматически распределяет отобранные тесты по потокам.

3. CI-системы:

- Кэшируйте .testmondata между билдами:

# GitHub Actions
- name: Cache testmon data
..uses: actions/cache@v3
..with:
....path: .testmondata
....key: testmon-${{ hashFiles('**/*.py') }}

Альтернативы и сравнение

pytest-testmon

  1. Анализ покрытия кода
  2. Высокая точность, простота
  3. Слепые зоны в динамике

pytest-picked

  1. Git-статус изменённых файлов
  2. Простая установка
  3. Нет связи тест-код

pytest-watch

  1. Запуск при изменении файлов
  2. Реактивность
  3. Нет интеллектуального отбора

unittest --failfast

  1. Остановка после первой ошибки
  2. Не требует настройки
  3. Экономия времени минимальна

Заключение: Когда и как внедрять testmon?

Идеальные кандидаты:

- Проекты с >200 тестами и временем прогона >5 минут.

- Команды, практикующие TDD/частыe рефакторинги.

- CI/CD пайплайны с длительным временем выполнения.

Стратегия внедрения:

1. Начните с установки в режиме "только сбор данных":

pytest --testmon --no-combined

2. Проведите 2-3 полных прогона для формирования базы.

3. Перейдите на умный запуск в CI и локально.

4. Добавьте в .testmonignore генерируемые файлы.

5. Настройте кеширование данных в CI.

Философский итог: testmon не заменяет тесты, а делает их выполнение осмысленным. Как сказал Кент Бек:

"Тесты — это не роскошь, а инструмент выживания в хаосе разработки. Оптимизируйте их, но не жертвуйте надёжностью".

# Ваша новая команда для повседневной работы
pytest --testmon -xvv # Быстро, с детализированным выводом и остановкой при первой ошибке

Официальная документация Примеры конфигов

Подписывайтесь:

Телеграм https://t.me/lets_go_code
Канал "Просто о программировании"
https://dzen.ru/lets_go_code