31. Configuración del proyecto con pyproject.toml o pytest.ini

31.1 Objetivo del tema

Cuando un proyecto crece, no conviene repetir siempre los mismos parámetros en la terminal. Pytest permite guardar configuración en archivos del proyecto.

En este tema veremos dos opciones habituales: pytest.ini y pyproject.toml.

Idea clave: una buena configuración hace que python -m pytest ejecute la suite con las opciones correctas por defecto.

31.2 Crear una carpeta de práctica

Crea un proyecto nuevo:

mkdir pytest-config-demo
cd pytest-config-demo

Instala las herramientas necesarias:

python -m pip install pytest pytest-cov

31.3 Crear una estructura de proyecto

Crea esta estructura:

mkdir src
mkdir src\tienda
mkdir tests
New-Item src\tienda\__init__.py -ItemType File
New-Item src\tienda\precios.py -ItemType File
New-Item tests\test_precios.py -ItemType File

La carpeta src contendrá el código y tests contendrá las pruebas.

31.4 Crear el módulo a probar

En src\tienda\precios.py escribe:

def aplicar_descuento(precio, porcentaje):
    if precio < 0:
        raise ValueError("El precio no puede ser negativo")
    if porcentaje < 0 or porcentaje > 100:
        raise ValueError("El porcentaje debe estar entre 0 y 100")
    return precio - (precio * porcentaje / 100)


def precio_final(precio, impuesto):
    if impuesto < 0:
        raise ValueError("El impuesto no puede ser negativo")
    return precio + (precio * impuesto / 100)

31.5 Crear pruebas

En tests\test_precios.py escribe:

import pytest

from tienda.precios import aplicar_descuento, precio_final


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


def test_aplicar_descuento_con_porcentaje_invalido():
    with pytest.raises(ValueError):
        aplicar_descuento(1000, 150)


def test_precio_final():
    assert precio_final(1000, 21) == 1210

31.6 El problema de la carpeta src

Si ejecutas directamente:

python -m pytest

Puede aparecer un error de importación porque Python no siempre encuentra el paquete dentro de src.

ModuleNotFoundError: No module named 'tienda'

Para este curso usaremos una solución simple configurando pythonpath en pytest.ini.

31.7 Crear pytest.ini

Crea un archivo pytest.ini en la raíz del proyecto:

[pytest]
pythonpath = src
testpaths = tests
addopts = -ra
markers =
    slow: pruebas lentas
    integration: pruebas de integración

Con esta configuración, pytest sabe dónde buscar código, dónde buscar pruebas y qué marcadores personalizados existen.

31.8 Qué hace pythonpath

La opción pythonpath = src agrega la carpeta src al camino de importación durante las pruebas.

from tienda.precios import aplicar_descuento

Gracias a esa configuración, el import anterior puede resolverse.

31.9 Qué hace testpaths

testpaths indica dónde buscar pruebas cuando ejecutas python -m pytest sin argumentos:

testpaths = tests

Esto evita que pytest recorra carpetas que no corresponden.

31.10 Qué hace addopts

addopts agrega opciones por defecto a cada ejecución:

addopts = -ra

La opción -ra muestra un resumen adicional de pruebas omitidas, fallos esperados y otros resultados relevantes.

31.11 Registrar marcadores

Como vimos en el tema anterior, conviene registrar marcadores personalizados:

markers =
    slow: pruebas lentas
    integration: pruebas de integración

Esto documenta los marcadores y evita advertencias de pytest.

31.12 Agregar cobertura a la configuración

Si quieres medir cobertura por defecto, puedes ampliar addopts:

[pytest]
pythonpath = src
testpaths = tests
addopts = -ra --cov=tienda --cov-report=term-missing
markers =
    slow: pruebas lentas
    integration: pruebas de integración

Ahora python -m pytest ejecutará pruebas y mostrará cobertura del paquete tienda.

31.13 Exigir cobertura mínima

También puedes agregar un umbral:

addopts = -ra --cov=tienda --cov-report=term-missing --cov-fail-under=80

Si la cobertura total queda por debajo de 80%, la ejecución fallará.

31.14 Configuración equivalente en pyproject.toml

En lugar de pytest.ini, puedes usar pyproject.toml:

[tool.pytest.ini_options]
pythonpath = ["src"]
testpaths = ["tests"]
addopts = "-ra --cov=tienda --cov-report=term-missing"
markers = [
    "slow: pruebas lentas",
    "integration: pruebas de integración",
]

pyproject.toml es común cuando varias herramientas del proyecto se configuran en un único archivo.

31.15 pytest.ini o pyproject.toml

Ambas opciones son válidas:

  • pytest.ini es simple, directo y fácil de leer.
  • pyproject.toml centraliza configuración de varias herramientas.

Para proyectos pequeños o cursos, pytest.ini suele ser suficiente. Para proyectos modernos con varias herramientas, pyproject.toml puede resultar más ordenado.

31.16 No dupliques configuración

Evita configurar lo mismo en varios archivos. Si tienes pytest.ini y pyproject.toml con opciones de pytest, puede ser confuso saber cuál se está usando.

Elige un archivo principal para configurar pytest y mantenlo claro.

31.17 Patrones de descubrimiento

Pytest busca por defecto archivos como test_*.py o *_test.py. Si necesitas cambiarlo:

[pytest]
python_files = test_*.py
python_classes = Test*
python_functions = test_*

En la mayoría de proyectos conviene respetar las convenciones por defecto.

31.18 Configurar warnings

También puedes controlar advertencias:

[pytest]
filterwarnings =
    error
    ignore::DeprecationWarning

Usar error convierte advertencias en errores. Puede ser útil en proyectos donde quieres detectar problemas temprano.

31.19 Archivo pytest.ini recomendado para la práctica

Para este ejemplo, deja pytest.ini así:

[pytest]
pythonpath = src
testpaths = tests
addopts = -ra --cov=tienda --cov-report=term-missing
markers =
    slow: pruebas lentas
    integration: pruebas de integración

Con esta configuración puedes ejecutar simplemente:

python -m pytest

31.20 Ver la configuración activa

Para comprobar qué archivo de configuración está usando pytest, ejecuta:

python -m pytest --trace-config

La salida es larga, pero ayuda a diagnosticar problemas de configuración.

31.21 Errores frecuentes

  • Duplicar configuración: usar pytest.ini y pyproject.toml con opciones distintas confunde.
  • Olvidar pythonpath con estructura src: puede aparecer ModuleNotFoundError.
  • Configurar demasiadas opciones en addopts: vuelve difícil entender qué hace una ejecución simple.
  • No registrar marcadores: pytest mostrará advertencias.
  • Copiar configuración sin entenderla: cada opción debe tener un motivo.

31.22 Comandos usados en este tema

mkdir pytest-config-demo
cd pytest-config-demo
python -m pip install pytest pytest-cov
mkdir src
mkdir src\tienda
mkdir tests
New-Item src\tienda\__init__.py -ItemType File
New-Item src\tienda\precios.py -ItemType File
New-Item tests\test_precios.py -ItemType File
python -m pytest
python -m pytest --trace-config

31.23 Qué debes recordar de este tema

  • pytest.ini y pyproject.toml pueden configurar pytest.
  • pythonpath ayuda a resolver imports en proyectos con carpeta src.
  • testpaths limita dónde pytest busca pruebas.
  • addopts define opciones por defecto.
  • Los marcadores personalizados deben registrarse.
  • Conviene elegir un solo archivo principal de configuración.

31.24 Conclusión

En este tema configuramos un proyecto de pruebas usando pytest.ini y vimos la alternativa con pyproject.toml. También revisamos opciones comunes como pythonpath, testpaths, addopts, marcadores y cobertura.

En el próximo tema veremos cómo ejecutar pruebas en distintas versiones de Python con tox.