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.
python -m pytest ejecute la suite con las opciones correctas por defecto.
Crea un proyecto nuevo:
mkdir pytest-config-demo
cd pytest-config-demo
Instala las herramientas necesarias:
python -m pip install pytest pytest-cov
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.
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)
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
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.
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.
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.
testpaths indica dónde buscar pruebas cuando ejecutas python -m pytest sin argumentos:
testpaths = tests
Esto evita que pytest recorra carpetas que no corresponden.
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.
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.
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.
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á.
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.
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.
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.
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.
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.
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
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.
pytest.ini y pyproject.toml con opciones distintas confunde.pythonpath con estructura src: puede aparecer ModuleNotFoundError.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
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.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.