Минимальное покрытие, pytest --cov-fail-under, интеграция в CI, quality gates
Pull request с новым кодом. Coverage упал с 85% до 70%. Код мержится. Через месяц — 50%. Как автоматически блокировать такое?
Цель: Настроить минимальные пороги покрытия и enforcement в CI.
Убедитесь, что умеете:
# Измерять coverage
pytest --cov=src --cov-report=html
# Читать метрики
# Name Stmts Miss Cover
# mymodule.py 50 10 80%Если coverage непонятен — вернитесь к pytest-junior урок 4.
# Week 1
pytest --cov=src
# Coverage: 85%
# Week 2 (добавлен код без тестов)
pytest --cov=src
# Coverage: 78%
# Week 4
pytest --cov=src
# Coverage: 65%
# Week 8
pytest --cov=src
# Coverage: 45% ❌Проблема: Покрытие падает незаметно, никто не замечает!
pytest --cov=src --cov-fail-under=80Если coverage < 80%:
---------- coverage: platform darwin, python 3.11 -----------
Name Stmts Miss Cover
---------------------------------
src/app.py 50 15 70%
---------------------------------
TOTAL 50 15 70%
FAIL Required test coverage of 80% not reached. Total coverage: 70.00%
❌ pytest завершается с exit code 1 — CI заблокирован!
# pytest.ini
[pytest]
addopts =
--cov=src
--cov-report=term-missing
--cov-report=html
--cov-fail-under=80 # Минимум 80%Теперь просто:
pytest✅ Всегда проверяет порог!
# pytest.ini (для локальной разработки)
[pytest]
addopts =
--cov=src
--cov-fail-under=70 # Мягкий порог локально# .gitlab-ci.yml (для CI)
test:
script:
- pytest --cov-fail-under=80 # Строгий порог в CIName Stmts Miss Cover
--------------------------------------------
src/core/auth.py 50 0 100% ✅
src/core/payments.py 50 40 20% ❌
--------------------------------------------
TOTAL 100 40 60% ⚠️
60% общего покрытия выглядит приемлемо, но payments — катастрофа!
# .coveragerc
[run]
source = src
omit =
*/tests/*
*/migrations/*
[report]
precision = 2
show_missing = True
# Минимальное покрытие для разных модулей
fail_under = 80
[coverage:paths]
source =
src/
# Per-module thresholds (через плагин)Плагин для per-module:
pip install coverage-conditional-plugin# .coveragerc
[coverage:run]
plugins = coverage_conditional_plugin
[coverage:paths:conditional]
# Критичные модули — 90%
src/payments/ = 90
src/auth/ = 90
# Обычные модули — 80%
src/api/ = 80
# UI/CLI — 60%
src/cli/ = 60# .gitlab-ci.yml
test:
stage: test
script:
- pip install -r requirements.txt
- pytest --cov=src --cov-fail-under=80 --cov-report=xml
- coverage report --fail-under=80
coverage: '/TOTAL.*\s+(\d+%)$/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml# .github/workflows/test.yml
- name: Run tests with coverage
run: |
pytest --cov=src --cov-fail-under=80 --cov-report=xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage.xml
fail_ci_if_error: true# codecov.yml
coverage:
status:
project:
default:
target: 80% # Минимум для всего проекта
threshold: 1% # Допустимое падение
patch:
default:
target: 90% # Новый код должен быть лучше!Результат: PR блокируется если:
# Быстрая проверка (без строгого порога)
pytest --cov=src
# Перед commit (строгий порог)
pytest --cov=src --cov-fail-under=75# .git/hooks/pre-commit
#!/bin/bash
pytest --cov=src --cov-fail-under=75 --cov-report=term-missing
if [ $? -ne 0 ]; then
echo "❌ Coverage is below 75%, commit blocked!"
exit 1
fi
echo "✅ Coverage check passed"stages:
- test
- quality-gate
- deploy
unit-tests:
stage: test
script:
- pytest --cov=src --cov-fail-under=70
coverage-check:
stage: quality-gate
script:
- pytest --cov=src --cov-fail-under=80
- coverage html
artifacts:
paths:
- htmlcov/
deploy:
stage: deploy
dependencies:
- coverage-check # Не задеплоим если coverage < 80%Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.
Далее: Практика: Production-ready проект