2. Preparación de un proyecto Python para medir cobertura

2.1 Objetivo del tema

Para medir cobertura necesitamos un proyecto ordenado: código de aplicación por un lado, pruebas por otro y dependencias instaladas en un entorno controlado. Si la estructura es confusa, los reportes de cobertura también serán confusos.

En este tema prepararemos un proyecto Python pequeño, pero realista, que usaremos en los próximos temas para ejecutar pruebas y medir cobertura con herramientas específicas.

Objetivo práctico: crear un proyecto con carpetas claras, código Python probado y una suite mínima lista para medir cobertura.

2.2 Crear la carpeta del proyecto

Desde la terminal, crea una carpeta para la práctica y entra en ella:

mkdir cobertura-demo
cd cobertura-demo

Usaremos esta carpeta como raíz del proyecto. Todos los comandos del tema se ejecutan desde esta ubicación, salvo que se indique lo contrario.

2.3 Crear un entorno virtual

Un entorno virtual evita mezclar dependencias de distintos proyectos. Créalo con:

python -m venv .venv

Luego actívalo. En Windows PowerShell:

.venv\Scripts\Activate.ps1

En Linux o macOS:

source .venv/bin/activate

Cuando el entorno está activo, la terminal suele mostrar (.venv) al comienzo de la línea.

2.4 Instalar pytest

En este tema todavía no instalaremos la herramienta de cobertura. Primero dejaremos funcionando la suite de pruebas con pytest:

python -m pip install --upgrade pip
python -m pip install pytest

Verifica la instalación:

python -m pytest --version
En los próximos temas agregaremos coverage.py y pytest-cov. Por ahora nos interesa que el proyecto pueda ejecutar pruebas correctamente.

2.5 Crear una estructura clara de carpetas

Crearemos una carpeta para el código de la aplicación y otra para las pruebas:

mkdir src
mkdir tests
mkdir src\tienda

En Linux o macOS, el último comando puede escribirse así:

mkdir -p src/tienda

La estructura inicial será:

cobertura-demo/
|-- .venv/
|-- src/
|   `-- tienda/
`-- tests/

2.6 Convertir la carpeta en un paquete Python

Dentro de src/tienda, crea un archivo vacío llamado __init__.py. Este archivo indica que tienda debe tratarse como un paquete Python.

En Windows PowerShell puedes crearlo con:

New-Item -ItemType File src\tienda\__init__.py

En Linux o macOS:

touch src/tienda/__init__.py

2.7 Crear el primer módulo de aplicación

Ahora crea el archivo src/tienda/precios.py con este contenido:

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

Este módulo tiene validaciones, cálculos y un ciclo. Es pequeño, pero suficiente para observar líneas cubiertas y no cubiertas cuando midamos cobertura.

2.8 Crear pruebas iniciales

Crea el archivo tests/test_precios.py:

import pytest

from tienda.precios import aplicar_descuento, calcular_total


def test_aplicar_descuento():
    assert aplicar_descuento(1000, 10) == 900


def test_aplicar_descuento_rechaza_precio_invalido():
    with pytest.raises(ValueError):
        aplicar_descuento(0, 10)


def test_calcular_total_con_items():
    items = [
        {"precio": 100, "cantidad": 2},
        {"precio": 50, "cantidad": 3},
    ]

    assert calcular_total(items) == 350

Estas pruebas no cubren todos los caminos del módulo. Esa decisión es intencional: en los próximos temas veremos cómo el reporte de cobertura nos ayuda a encontrar lo que falta.

2.9 Configurar PYTHONPATH para ejecutar las pruebas

Como el código está dentro de la carpeta src, Python debe poder encontrar el paquete tienda. Una forma simple para esta práctica es definir PYTHONPATH al ejecutar las pruebas.

En Windows PowerShell:

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

En Linux o macOS:

PYTHONPATH=src python -m pytest

Si todo está correcto, las pruebas deben pasar.

2.10 Resultado esperado de pytest

La salida exacta puede variar según la versión, pero debería mostrar que se ejecutaron tres pruebas correctamente:

3 passed

Este resultado solo confirma que las pruebas pasan. Todavía no sabemos qué partes del módulo quedaron sin ejecutar. Esa información aparecerá cuando midamos cobertura.

2.11 Agregar un archivo requirements.txt

Para registrar las dependencias mínimas de este proyecto, crea un archivo requirements.txt con este contenido:

pytest

Más adelante agregaremos las herramientas de cobertura. Por ahora, este archivo expresa que el proyecto necesita pytest para ejecutar sus pruebas.

2.12 Estructura final del proyecto

Al terminar el tema, la estructura debería quedar así:

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

Esta organización separa claramente el código productivo de las pruebas. Esa separación facilita leer los reportes de cobertura y evita medir archivos equivocados.

2.13 Qué comportamientos todavía faltan probar

Antes de usar herramientas automáticas, conviene mirar el código y razonar. En nuestro ejemplo todavía faltan pruebas para varios casos:

  • Porcentaje de descuento menor que 0.
  • Porcentaje de descuento mayor que 100.
  • Lista vacía en calcular_total.
  • Casos límite como descuento de 0% y 100%.

La cobertura nos ayudará a confirmar estas ausencias, pero el análisis humano sigue siendo necesario para decidir qué pruebas tienen sentido.

2.14 Problemas frecuentes

  • No se encuentra el paquete tienda: revisa que estés configurando PYTHONPATH=src o $env:PYTHONPATH="src" antes de ejecutar pytest.
  • No se descubren las pruebas: verifica que la carpeta se llame tests y el archivo comience con test_.
  • pytest no se reconoce: activa el entorno virtual o ejecuta python -m pytest.
  • Errores por rutas: ejecuta los comandos desde la carpeta raíz cobertura-demo.

2.15 Conclusión

En este tema dejamos listo un proyecto Python preparado para medir cobertura: creamos carpetas, un paquete dentro de src, un módulo con lógica de negocio y una suite inicial de pruebas con pytest.

También vimos que las pruebas pasan, pero aún no sabemos qué líneas quedaron sin ejecutar. En el próximo tema instalaremos coverage.py y haremos la primera medición real desde la terminal.