19. Fallar la ejecución cuando la cobertura baja del mínimo esperado

19.1 Objetivo del tema

Medir cobertura sirve para observar el estado actual del proyecto. Pero en equipos y proyectos con integración continua también suele interesar impedir que la cobertura baje por accidente.

En este tema vamos a configurar un mínimo de cobertura. Si el reporte queda por debajo de ese valor, el comando termina con error.

Objetivo práctico: usar fail_under y --cov-fail-under para proteger un mínimo de cobertura.

19.2 Por qué usar un mínimo

Un mínimo de cobertura ayuda a detectar regresiones. Por ejemplo, si el proyecto suele estar en 85% y un cambio lo baja a 70%, conviene revisar qué ocurrió antes de integrar ese cambio.

El objetivo no es perseguir un número perfecto. El objetivo es evitar que zonas ya cubiertas se pierdan silenciosamente.

19.3 Ejecutar coverage con fail-under

Con coverage.py puedes indicar el mínimo al generar el reporte:

python -m coverage run -m pytest
python -m coverage report --fail-under=80

Si la cobertura total es menor que 80%, el segundo comando falla.

Una salida posible es:

TOTAL                      120     30    75%
Coverage failure: total of 75 is less than fail-under=80

19.4 Configurar fail_under en pyproject.toml

Para no repetir el valor en cada comando, puedes configurarlo:

[tool.coverage.run]
source = ["src"]
branch = true

[tool.coverage.report]
show_missing = true
fail_under = 80

Luego basta con ejecutar:

python -m coverage run -m pytest
python -m coverage report

Coverage usará el mínimo definido en la configuración.

19.5 Usar pytest-cov con cov-fail-under

Con pytest-cov, puedes usar --cov-fail-under:

En Windows PowerShell:

$env:PYTHONPATH="src"
python -m pytest --cov=src --cov-report=term-missing --cov-fail-under=80

En Linux o macOS:

PYTHONPATH=src python -m pytest --cov=src --cov-report=term-missing --cov-fail-under=80

Si la cobertura queda por debajo del mínimo, pytest termina con código de error.

19.6 Qué significa que falle

Cuando falla por cobertura, no significa que las pruebas hayan fallado por una aserción. Significa que el porcentaje total quedó por debajo del umbral.

En un flujo automatizado, eso es útil porque bloquea cambios que reducen cobertura más allá de lo aceptado.

El mensaje suele indicar algo como:

FAIL Required test coverage of 80% not reached. Total coverage: 76.25%

19.7 Elegir un umbral inicial

Un error común es elegir un mínimo irrealista. Si el proyecto hoy tiene 62%, configurar 95% solo hará que el chequeo falle siempre.

Una estrategia razonable:

  • Medir la cobertura actual.
  • Configurar un mínimo apenas por debajo o igual al valor actual.
  • Subir el mínimo gradualmente cuando se agregan pruebas reales.
  • No bajar el mínimo sin una razón explícita.

19.8 Ejemplo de evolución gradual

Supongamos que el proyecto está en 72%. Podrías empezar así:

[tool.coverage.report]
fail_under = 70

Luego, cuando el proyecto mejore:

[tool.coverage.report]
fail_under = 75

Este enfoque protege avances sin convertir el número en una meta artificial.

19.9 No usar el mínimo como único criterio

Un mínimo global puede ocultar zonas críticas sin cubrir. Por ejemplo, un proyecto puede tener 90% total y aun así tener el módulo de pagos en 40%.

El mínimo global es una barrera básica, no un reemplazo del análisis por módulo. En el próximo tema veremos cómo priorizar zonas críticas.

19.10 Configuración recomendada

Una configuración práctica para continuar el curso:

[tool.coverage.run]
source = ["src"]
branch = true
omit = [
    "*/__init__.py",
]

[tool.coverage.report]
show_missing = true
precision = 2
fail_under = 80

Ajusta fail_under al estado real de tu proyecto.

19.11 Usar en integración continua

En una integración continua, el comando puede ser:

python -m pytest --cov=src --cov-branch --cov-report=term-missing --cov-fail-under=80

Si el comando termina con error, la ejecución de CI falla y el cambio debe revisarse.

Si ya configuraste fail_under y branch en pyproject.toml, el comando puede simplificarse:

python -m pytest --cov --cov-report=term-missing

19.12 Qué hacer cuando falla el mínimo

Cuando el mínimo falla, revisa el reporte antes de cambiar el umbral.

  • Si faltan pruebas importantes: agrégalas.
  • Si se incluyeron archivos no deseados: corrige source u omit.
  • Si el código nuevo todavía no está listo: evita integrarlo hasta cubrirlo razonablemente.
  • Si el umbral era incorrecto: ajusta el valor y deja clara la razón.

19.13 Errores frecuentes

  • Poner un umbral demasiado alto al inicio: hace que la regla sea ignorada o desactivada.
  • Bajar el mínimo para pasar rápido: debilita el valor del chequeo.
  • Mirar solo el total: un total alto puede esconder módulos críticos con poca cobertura.
  • Confundir fallo de pruebas con fallo de cobertura: lee el mensaje para saber qué falló.

19.14 Conclusión

En este tema configuramos un mínimo de cobertura con --fail-under, fail_under y --cov-fail-under. Esta regla ayuda a evitar que la cobertura baje sin que nadie lo note.

En el próximo tema vamos a analizar cobertura por módulo para priorizar zonas críticas del sistema.