Un reporte de cobertura es útil cuando mide el código correcto. Si incluye pruebas, archivos generados o scripts manuales, el porcentaje puede volverse confuso.
En este tema vamos a definir criterios para decidir qué archivos medir y cuáles dejar fuera del reporte.
La cobertura suele medir el código que queremos proteger con pruebas automatizadas: módulos de dominio, validaciones, servicios, funciones puras, clases y reglas de negocio.
En el proyecto del curso, eso corresponde principalmente a:
src/
`-- tienda/
|-- tarifas.py
|-- cupones.py
|-- carrito.py
`-- ...
Los tests ejecutan ese código, pero no suelen ser el objetivo principal del porcentaje de cobertura.
Si coverage mide tests, el porcentaje total puede subir o bajar por razones poco útiles. Los tests son importantes, pero medir su propia cobertura no responde la pregunta principal.
La pregunta que nos interesa es:
Por eso conviene configurar source = ["src"] o usar --cov=src.
En pyproject.toml:
[tool.coverage.run]
source = ["src"]
branch = true
Con esta configuración, coverage se concentra en el código de src.
Luego puedes ejecutar:
python -m coverage run -m pytest
python -m coverage report
Con pytest-cov, puedes indicar explícitamente qué medir:
En Windows PowerShell:
$env:PYTHONPATH="src"
python -m pytest --cov=src --cov-report=term-missing
En Linux o macOS:
PYTHONPATH=src python -m pytest --cov=src --cov-report=term-missing
Así los tests se ejecutan, pero el reporte se enfoca en src.
Un proyecto puede tener scripts para tareas manuales:
scripts/
|-- cargar_datos_demo.py
|-- limpiar_temporales.py
`-- generar_reporte_manual.py
No siempre conviene medirlos con la misma regla que el código de aplicación. Algunos se ejecutan manualmente, dependen de archivos locales o solo preparan datos de desarrollo.
Si no son parte del comportamiento principal, puedes excluirlos:
[tool.coverage.run]
source = ["src"]
omit = [
"*/scripts/*",
]
El código generado por herramientas no suele editarse a mano. Ejemplos habituales:
Si el archivo se regenera automáticamente, normalmente no tiene sentido perseguir cobertura línea por línea sobre él.
Un ejemplo de configuración:
[tool.coverage.run]
source = ["src"]
branch = true
omit = [
"*/migrations/*",
"*/generated/*",
"*/_generated.py",
]
Los patrones deben ajustarse a la estructura real del proyecto. No copies exclusiones que no necesitas.
Muchos archivos __init__.py están vacíos o solo declaran el paquete. En esos casos, medirlos aporta poco.
omit = [
"*/__init__.py",
]
Pero si un __init__.py contiene lógica real, no lo excluyas automáticamente. La regla depende del contenido.
Excluir archivos debe reducir ruido, no esconder problemas. Si un archivo contiene reglas de negocio, validaciones o lógica crítica, debería estar medido.
Una mala exclusión sería:
omit = [
"src/tienda/pagos.py",
]
Si pagos.py contiene reglas importantes, excluirlo solo mejora el porcentaje en apariencia y empeora la utilidad del reporte.
omit excluye archivos completos o grupos de archivos. pragma: no cover excluye líneas o bloques puntuales.
Después de cambiar source u omit, ejecuta:
python -m coverage erase
python -m coverage run -m pytest
python -m coverage report
Revisa que aparezcan los archivos esperados y que no desaparezca código importante.
Los resultados generados por coverage no deberían versionarse:
.coverage
htmlcov/
Esto no afecta qué se mide. Solo evita subir al repositorio archivos generados localmente.
source = ["src"] o usa --cov=src.omit demasiado amplios.En este tema definimos qué archivos conviene medir y cuáles pueden quedar fuera del reporte. La configuración debe enfocar coverage en el código de aplicación sin ocultar lógica importante.
En el próximo tema vamos a configurar un mínimo de cobertura para que la ejecución falle cuando el porcentaje baje de lo esperado.