3. Instalación de coverage.py y primera medición desde la terminal

3.1 Objetivo del tema

En el tema anterior dejamos listo un proyecto Python con código en src y pruebas en tests. Ahora instalaremos coverage.py, ejecutaremos las pruebas bajo medición y generaremos el primer reporte de cobertura desde la terminal.

El objetivo no es alcanzar 100% de cobertura todavía. Primero necesitamos entender el flujo básico: instalar la herramienta, ejecutar las pruebas, generar el reporte y leer los resultados principales.

Objetivo práctico: obtener el primer porcentaje de cobertura del proyecto y detectar qué líneas del módulo quedaron sin ejecutar.

3.2 Punto de partida

Trabajaremos sobre el proyecto cobertura-demo creado en el tema anterior. Antes de continuar, entra en la carpeta y activa el entorno virtual.

En Windows PowerShell:

cd cobertura-demo
.venv\Scripts\Activate.ps1

En Linux o macOS:

cd cobertura-demo
source .venv/bin/activate

La estructura esperada es:

cobertura-demo/
|-- .venv/
|-- requirements.txt
|-- src/
|   `-- tienda/
|       |-- __init__.py
|       `-- precios.py
`-- tests/
    `-- test_precios.py

3.3 Verificar que las pruebas pasan

Antes de medir cobertura, confirma que la suite de pruebas funciona. En Windows PowerShell:

$env:PYTHONPATH="src"
python -m pytest

En Linux o macOS:

PYTHONPATH=src python -m pytest

Debes obtener una salida similar a:

3 passed
Conviene medir cobertura solo cuando las pruebas pasan. Si la suite falla, primero corrige la suite o el código de aplicación.

3.4 Instalar coverage.py

Con el entorno virtual activo, instala coverage.py:

python -m pip install coverage

Luego verifica la instalación:

python -m coverage --version

Una salida válida mostrará la versión instalada de coverage.py. El número exacto puede variar.

3.5 Actualizar requirements.txt

Agrega coverage al archivo requirements.txt para que el proyecto declare sus dependencias de pruebas:

pytest
coverage

Otra opción es regenerar el archivo con:

python -m pip freeze > requirements.txt

Para ejercicios didácticos suele ser más claro escribir solo las dependencias principales. En proyectos reales puede convenir fijar versiones exactas.

3.6 Ejecutar pytest bajo coverage

Para medir cobertura, ejecutamos las pruebas mediante coverage run. En Windows PowerShell:

$env:PYTHONPATH="src"
python -m coverage run -m pytest

En Linux o macOS:

PYTHONPATH=src python -m coverage run -m pytest

La parte -m pytest indica que coverage debe ejecutar el módulo pytest. Es decir: las pruebas corren igual que antes, pero ahora se registra qué código se ejecutó.

3.7 El archivo .coverage

Después de ejecutar el comando anterior, aparecerá un archivo llamado .coverage en la raíz del proyecto.

Ese archivo contiene los datos crudos de la medición. No se lee manualmente; se usa como entrada para generar reportes.

cobertura-demo/
|-- .coverage
|-- requirements.txt
|-- src/
`-- tests/
El archivo .coverage es un resultado generado. Normalmente no se edita a mano ni se usa para explicar el comportamiento del programa.

3.8 Generar el reporte básico

Para ver el reporte en la terminal, ejecuta:

python -m coverage report

Luego de ejecutar el comando, se obtuvo esta salida:

Name                     Stmts   Miss  Cover
--------------------------------------------
src\tienda\__init__.py       0      0   100%
src\tienda\precios.py       14      2    86%
tests\test_precios.py       10      0   100%
--------------------------------------------
TOTAL                       24      2    92%

En este caso, el reporte muestra una cobertura total del 92% y dos sentencias sin ejecutar.

Reporte básico de cobertura generado desde la terminal

3.9 Qué significa cada columna

  • Name: archivo analizado.
  • Stmts: cantidad de sentencias ejecutables detectadas.
  • Miss: cantidad de sentencias que no se ejecutaron.
  • Cover: porcentaje de sentencias ejecutadas.

En el ejemplo, src/tienda/precios.py tiene líneas sin cubrir. Eso coincide con lo que ya habíamos razonado: faltan pruebas para algunos caminos.

3.10 Ver las líneas faltantes

El reporte básico muestra el porcentaje, pero no dice cuáles son las líneas faltantes. Para verlas, usa la opción -m:

python -m coverage report -m

La salida agrega una columna Missing:

Name                     Stmts   Miss  Cover   Missing
------------------------------------------------------
src\tienda\__init__.py       0      0   100%
src\tienda\precios.py       14      2    86%   6, 14
tests\test_precios.py       10      0   100%
------------------------------------------------------
TOTAL                       24      2    92%

Los números de línea indican dónde quedaron partes del código sin ejecutar durante la suite. En este caso, las líneas faltantes son la 6 y la 14 de src\tienda\precios.py.

3.11 Revisar el código con el reporte

Volvamos al módulo src/tienda/precios.py:

def aplicar_descuento(precio, porcentaje):
    if precio <= 0:
        raise ValueError("El precio debe ser mayor que cero")

    if porcentaje < 0 or porcentaje > 100:
        raise ValueError("El porcentaje debe estar entre 0 y 100")

    descuento = precio * porcentaje / 100
    return precio - descuento


def calcular_total(items):
    if not items:
        return 0

    total = 0
    for item in items:
        total += item["precio"] * item["cantidad"]

    return total

Las líneas faltantes corresponden a caminos no probados: porcentaje inválido y lista vacía. El reporte confirma dónde conviene agregar nuevas pruebas.

3.12 Agregar pruebas para mejorar la cobertura

Agrega estas pruebas al archivo tests/test_precios.py:

def test_aplicar_descuento_rechaza_porcentaje_menor_que_cero():
    with pytest.raises(ValueError):
        aplicar_descuento(1000, -1)


def test_aplicar_descuento_rechaza_porcentaje_mayor_que_cien():
    with pytest.raises(ValueError):
        aplicar_descuento(1000, 101)


def test_calcular_total_sin_items():
    assert calcular_total([]) == 0

Estas pruebas no se escriben para perseguir un número. Se escriben porque representan comportamientos reales que no estaban verificados.

3.13 Medir nuevamente

Ejecuta otra vez las pruebas con cobertura. En Windows PowerShell:

$env:PYTHONPATH="src"
python -m coverage run -m pytest
python -m coverage report -m

En Linux o macOS:

PYTHONPATH=src python -m coverage run -m pytest
python -m coverage report -m

Ahora el porcentaje debería subir y la lista de líneas faltantes debería reducirse o desaparecer para precios.py.

Reporte de cobertura luego de agregar nuevas pruebas

3.14 Limpiar datos de cobertura

Si quieres borrar los datos acumulados de cobertura, ejecuta:

python -m coverage erase

Esto elimina el archivo .coverage. Luego puedes volver a medir desde cero ejecutando python -m coverage run -m pytest.

3.15 Problemas frecuentes

  • No module named coverage: instala la herramienta dentro del entorno virtual activo con python -m pip install coverage.
  • No module named tienda: revisa que PYTHONPATH apunte a src.
  • No data to report: primero ejecuta python -m coverage run -m pytest y luego python -m coverage report.
  • El reporte incluye archivos no deseados: más adelante configuraremos qué fuentes medir y qué archivos omitir.

3.16 Conclusión

En este tema instalamos coverage.py, ejecutamos las pruebas bajo medición con coverage run -m pytest y generamos el primer reporte con coverage report.

También usamos coverage report -m para localizar líneas faltantes y agregamos pruebas a partir de esa información. En el próximo tema profundizaremos en la ejecución con coverage run y en la generación del reporte básico.