Un proyecto puede funcionar en una versión de Python y fallar en otra. Si una librería declara compatibilidad con varias versiones, conviene ejecutar la misma suite en cada una.
tox automatiza ese trabajo: crea entornos aislados, instala dependencias y ejecuta comandos de prueba.
tox ayuda a comprobar que el proyecto se prueba igual en distintos entornos.
Crea un proyecto nuevo:
mkdir tox-demo
cd tox-demo
Instala las herramientas necesarias en tu entorno principal:
python -m pip install pytest tox
Crea estas carpetas y archivos:
mkdir src
mkdir src\calculadora
mkdir tests
New-Item src\calculadora\__init__.py -ItemType File
New-Item src\calculadora\operaciones.py -ItemType File
New-Item tests\test_operaciones.py -ItemType File
En src\calculadora\operaciones.py escribe:
def sumar(a, b):
return a + b
def dividir(a, b):
if b == 0:
raise ValueError("No se puede dividir por cero")
return a / b
def promedio(numeros):
if not numeros:
raise ValueError("La lista no puede estar vacía")
return sum(numeros) / len(numeros)
En tests\test_operaciones.py escribe:
import pytest
from calculadora.operaciones import dividir, promedio, sumar
def test_sumar():
assert sumar(2, 3) == 5
def test_dividir():
assert dividir(10, 2) == 5
def test_dividir_por_cero():
with pytest.raises(ValueError):
dividir(10, 0)
def test_promedio():
assert promedio([10, 20, 30]) == 20
def test_promedio_lista_vacia():
with pytest.raises(ValueError):
promedio([])
Para que pytest encuentre el paquete dentro de src, crea pytest.ini:
[pytest]
pythonpath = src
testpaths = tests
addopts = -ra
Esto permite ejecutar pruebas localmente con:
python -m pytest
Crea un archivo tox.ini en la raíz:
[tox]
envlist = py310, py311, py312
skip_missing_interpreters = true
[testenv]
deps =
pytest
commands =
python -m pytest
envlist define los entornos que tox intentará ejecutar.
[tox]: configuración general de tox.envlist: lista de versiones o entornos a ejecutar.skip_missing_interpreters: omite versiones de Python que no estén instaladas.[testenv]: configuración común para cada entorno.deps: dependencias que tox instala dentro del entorno.commands: comandos que tox ejecuta.Ejecuta:
python -m tox
tox creará una carpeta .tox con entornos aislados y ejecutará las pruebas en cada versión disponible.
py310: skipped because could not find python interpreter
py311: OK
py312: OK
congratulations :)
La salida exacta depende de las versiones instaladas en tu equipo.
Para ejecutar solo un entorno:
python -m tox -e py312
Esto es útil cuando estás corrigiendo una falla específica de una versión.
Podemos permitir que tox pase argumentos extra a pytest. Modifica tox.ini:
[testenv]
deps =
pytest
commands =
python -m pytest {posargs}
Ahora puedes ejecutar una prueba concreta:
python -m tox -e py312 -- tests/test_operaciones.py::test_sumar
Si quieres medir cobertura dentro de tox:
[testenv]
deps =
pytest
pytest-cov
commands =
python -m pytest --cov=calculadora --cov-report=term-missing {posargs}
tox instalará pytest-cov dentro de cada entorno antes de ejecutar las pruebas.
En proyectos simples puedes listar dependencias en deps. Si usas un archivo requirements-dev.txt:
[testenv]
deps =
-r requirements-dev.txt
commands =
python -m pytest {posargs}
Esto evita duplicar dependencias en varios lugares.
Algunas pruebas necesitan variables de entorno. Puedes definirlas con setenv:
[testenv]
setenv =
APP_ENV = test
API_URL = https://example.test
deps =
pytest
commands =
python -m pytest
Estas variables existen dentro del entorno de tox.
tox espera comandos controlados dentro del entorno. Si necesitas ejecutar un comando externo, puede requerir configuración adicional. En general, para este curso alcanza con:
commands =
python -m pytest
Usar python -m pytest evita depender de rutas concretas del ejecutable pytest.
También puedes configurar tox en pyproject.toml:
[tool.tox]
legacy_tox_ini = """
[tox]
envlist = py310, py311, py312
skip_missing_interpreters = true
[testenv]
deps =
pytest
commands =
python -m pytest {posargs}
"""
Para empezar, tox.ini suele ser más directo y fácil de leer.
Para la práctica, puedes dejar tox.ini así:
[tox]
envlist = py310, py311, py312
skip_missing_interpreters = true
[testenv]
deps =
pytest
pytest-cov
commands =
python -m pytest --cov=calculadora --cov-report=term-missing {posargs}
tox es especialmente útil cuando:
tox crea entornos usando intérpretes disponibles en tu sistema. Si configuras py310 pero no tienes Python 3.10 instalado, ese entorno no podrá ejecutarse.
skip_missing_interpreters = true evita que la ejecución falle solo porque una versión no está instalada.
{posargs}: limita la posibilidad de ejecutar pruebas específicas.mkdir tox-demo
cd tox-demo
python -m pip install pytest tox
mkdir src
mkdir src\calculadora
mkdir tests
New-Item src\calculadora\__init__.py -ItemType File
New-Item src\calculadora\operaciones.py -ItemType File
New-Item tests\test_operaciones.py -ItemType File
python -m pytest
python -m tox
python -m tox -e py312
python -m tox -e py312 -- tests/test_operaciones.py::test_sumar
tox ejecuta comandos en entornos aislados.envlist define qué entornos se ejecutan.deps instala dependencias dentro de cada entorno.commands define qué se ejecuta.{posargs} permite pasar argumentos extra.En este tema configuramos tox para ejecutar pruebas en distintas versiones de Python, definir dependencias, pasar argumentos a pytest y agregar cobertura.
En el próximo tema veremos cómo integrar pruebas con formateo y análisis estático básico.