21. Combinar resultados de cobertura de varias ejecuciones

21.1 Objetivo del tema

A veces la cobertura se obtiene en más de una ejecución: pruebas unitarias por un lado, pruebas de integración por otro, o la misma suite ejecutada en distintos sistemas operativos.

En este tema vamos a combinar esos resultados para obtener un reporte consolidado.

Objetivo práctico: generar varios archivos de cobertura y unirlos con python -m coverage combine.

21.2 Cuándo hace falta combinar

No siempre necesitas combinar cobertura. Es útil cuando el proyecto ejecuta pruebas en grupos separados.

  • Unitarias e integración: se ejecutan con comandos distintos.
  • Distintos entornos: Windows, Linux o varias versiones de Python.
  • Procesos paralelos: cada proceso genera su propio archivo de datos.
  • Suites costosas: se dividen para acelerar la ejecución.

21.3 El problema de sobrescribir .coverage

Si ejecutas dos mediciones normales, la segunda puede sobrescribir los datos de la primera:

python -m coverage run -m pytest tests/unit
python -m coverage run -m pytest tests/integration

Al final podrías tener cobertura solo de la última ejecución. Para evitarlo, usamos modo paralelo.

21.4 Activar parallel

En pyproject.toml, agrega parallel = true:

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

Con esta opción, coverage no escribe solo .coverage. Genera archivos con nombres únicos:

.coverage.DESKTOP.12345.Xabc
.coverage.DESKTOP.12346.Ydef

21.5 Ejecutar varias mediciones

Ahora puedes ejecutar grupos separados:

python -m coverage erase
python -m coverage run -m pytest tests/unit
python -m coverage run -m pytest tests/integration

Cada ejecución guardará sus datos en un archivo separado gracias a parallel = true.

21.6 Combinar resultados

Para unir todos los archivos de datos, ejecuta:

python -m coverage combine

Coverage lee los archivos .coverage.* y genera un archivo combinado .coverage.

Luego puedes crear el reporte:

python -m coverage report -m

21.7 Flujo completo

Una secuencia completa sería:

python -m coverage erase
python -m coverage run -m pytest tests/unit
python -m coverage run -m pytest tests/integration
python -m coverage combine
python -m coverage report -m

Si quieres reporte HTML:

python -m coverage html

21.8 Ejemplo conceptual

Supongamos que las pruebas unitarias cubren funciones puras y las de integración cubren flujos completos:

tests/unit/test_tarifas.py
tests/unit/test_cupones.py
tests/integration/test_compra_completa.py

Por separado, cada suite muestra una parte del sistema. Al combinarlas, el reporte refleja todo lo ejecutado entre ambas.

21.9 Usar pytest-cov

Con pytest-cov, muchas veces el plugin maneja la combinación cuando ejecuta pruebas en paralelo dentro del mismo comando. Pero si haces ejecuciones separadas, sigue siendo útil entender coverage combine.

Una alternativa es generar datos con coverage.py directamente para tener control explícito del flujo.

21.10 Combinar en CI

En integración continua, puede haber varios trabajos que generan artefactos de cobertura. El flujo general es:

  • Cada trabajo ejecuta pruebas con coverage en modo paralelo.
  • Cada trabajo guarda sus archivos .coverage.* como artefactos.
  • Un trabajo final descarga los artefactos.
  • Ese trabajo ejecuta coverage combine y genera el reporte final.

El detalle exacto depende de la plataforma de CI, pero la idea es siempre la misma.

21.11 Revisar archivos generados

Después de las ejecuciones, puedes listar los archivos de cobertura:

dir .coverage*

En Linux o macOS:

ls -a .coverage*

Si solo ves .coverage, quizá no está activo parallel = true o ya ejecutaste coverage combine.

21.12 Borrar datos anteriores

Antes de una medición limpia, ejecuta:

python -m coverage erase

Esto elimina datos anteriores y evita mezclar resultados viejos con una corrida nueva.

21.13 Problemas frecuentes

  • No data to combine: no hay archivos .coverage.* para unir.
  • Solo aparece la última ejecución: activa parallel = true.
  • El reporte mezcla datos viejos: ejecuta python -m coverage erase antes de empezar.
  • Rutas distintas entre entornos: puede hacer falta configurar equivalencias de rutas en proyectos avanzados.

21.14 Conclusión

En este tema vimos cómo combinar resultados de cobertura de varias ejecuciones con parallel = true y python -m coverage combine.

En el próximo tema vamos a revisar errores frecuentes al medir cobertura y cómo corregirlos.