En proyectos reales no siempre queremos ejecutar todas las pruebas. Mientras corregimos un error, suele ser más rápido ejecutar una prueba específica. Antes de terminar, conviene ejecutar toda la suite.
En este tema veremos cómo ejecutar todas las pruebas, una carpeta, un archivo, una clase y una función puntual usando pytest.
::.
Crea un proyecto nuevo:
mkdir pytest-ejecucion-demo
cd pytest-ejecucion-demo
Si pytest no está instalado en el entorno activo, instálalo:
python -m pip install pytest
Crea estas carpetas:
mkdir app
mkdir tests
mkdir tests\unit
mkdir tests\integration
En Linux o macOS:
mkdir -p app tests/unit tests/integration
Dentro de app, crea calculadora.py:
def sumar(a, b):
return a + b
def restar(a, b):
return a - b
def dividir(a, b):
if b == 0:
raise ValueError("No se puede dividir por cero")
return a / b
Ahora crea app\usuarios.py:
def normalizar_nombre(nombre):
return nombre.strip().title()
def es_mayor_de_edad(edad):
return edad >= 18
Dentro de tests\unit, crea test_calculadora.py:
import pytest
from app.calculadora import dividir, restar, sumar
def test_sumar():
assert sumar(2, 3) == 5
def test_restar():
assert restar(10, 4) == 6
def test_dividir():
assert dividir(10, 2) == 5
def test_dividir_por_cero_lanza_error():
with pytest.raises(ValueError):
dividir(10, 0)
Dentro de tests\unit, crea test_usuarios.py:
from app.usuarios import es_mayor_de_edad, normalizar_nombre
def test_normalizar_nombre():
assert normalizar_nombre(" ana ") == "Ana"
def test_edad_18_es_mayor_de_edad():
assert es_mayor_de_edad(18) is True
def test_edad_17_no_es_mayor_de_edad():
assert es_mayor_de_edad(17) is False
Dentro de tests\integration, crea test_flujo_usuario.py:
from app.calculadora import sumar
from app.usuarios import normalizar_nombre
def test_flujo_registro_con_puntaje():
nombre = normalizar_nombre(" ana ")
puntaje = sumar(40, 2)
assert nombre == "Ana"
assert puntaje == 42
La carpeta integration representa pruebas que combinan más de una parte del código.
Desde la raíz del proyecto, ejecuta:
python -m pytest
La salida esperada será similar a:
collected 8 items
tests/integration/test_flujo_usuario.py . [ 12%]
tests/unit/test_calculadora.py .... [ 62%]
tests/unit/test_usuarios.py ... [100%]
8 passed in 0.03s
Para ejecutar solo las pruebas unitarias:
python -m pytest tests\unit
En Linux o macOS:
python -m pytest tests/unit
Para ejecutar solo las pruebas de integración:
python -m pytest tests\integration
Para ejecutar solamente las pruebas de calculadora:
python -m pytest tests\unit\test_calculadora.py
En Linux o macOS:
python -m pytest tests/unit/test_calculadora.py
Esto ejecuta todas las funciones de prueba dentro de ese archivo.
Para ejecutar una sola función de prueba, usa :: después de la ruta del archivo:
python -m pytest tests\unit\test_calculadora.py::test_dividir_por_cero_lanza_error
Este comando es muy útil mientras corriges una regla puntual.
La opción -v muestra el nombre de cada prueba:
python -m pytest -v
También puede combinarse con una ruta específica:
python -m pytest tests\unit\test_usuarios.py -v
Podemos combinar ruta, nombre de prueba y -v:
python -m pytest tests\unit\test_usuarios.py::test_edad_18_es_mayor_de_edad -v
La salida indicará explícitamente esa prueba y su resultado.
La opción -k permite seleccionar pruebas cuyo nombre contiene una expresión:
python -m pytest -k edad
Este comando ejecuta pruebas con edad en el nombre, como test_edad_18_es_mayor_de_edad y test_edad_17_no_es_mayor_de_edad.
También podemos excluir coincidencias:
python -m pytest -k "not edad"
Esto ejecuta las pruebas cuyo nombre no coincide con edad.
La opción -x detiene la suite cuando aparece la primera falla:
python -m pytest -x
Es útil cuando una falla inicial puede provocar muchas fallas derivadas.
Después de una ejecución con fallas, pytest puede repetir solo las que fallaron con:
python -m pytest --lf
--lf significa last failed. Es práctico durante ciclos de corrección.
| Objetivo | Comando |
|---|---|
| Toda la suite | python -m pytest |
| Una carpeta | python -m pytest tests\unit |
| Un archivo | python -m pytest tests\unit\test_calculadora.py |
| Una prueba | python -m pytest tests\unit\test_calculadora.py::test_sumar |
| Por nombre | python -m pytest -k edad |
| Detener en primera falla | python -m pytest -x |
pytest-ejecucion-demo/
|-- app/
| |-- calculadora.py
| `-- usuarios.py
`-- tests/
|-- integration/
| `-- test_flujo_usuario.py
`-- unit/
|-- test_calculadora.py
`-- test_usuarios.py
Esta organización permite ejecutar grupos completos de pruebas por carpeta.
from app....::: pytest no encontrará esa prueba.\, en Linux y macOS se usa /.-k con una palabra demasiado amplia: puede ejecutar más pruebas de las esperadas.mkdir pytest-ejecucion-demo
cd pytest-ejecucion-demo
python -m pip install pytest
mkdir app
mkdir tests
mkdir tests\unit
mkdir tests\integration
python -m pytest
python -m pytest tests\unit
python -m pytest tests\unit\test_calculadora.py
python -m pytest tests\unit\test_calculadora.py::test_dividir_por_cero_lanza_error
python -m pytest -v
python -m pytest -k edad
python -m pytest -x
python -m pytest --lf
python -m pytest ejecuta toda la suite descubierta.:: permite apuntar a una prueba específica.-k selecciona pruebas por nombre.En este tema aprendimos a ejecutar pruebas con distintos niveles de precisión: toda la suite, una carpeta, un archivo o una prueba puntual. Esto permite trabajar rápido durante el desarrollo y verificar todo antes de cerrar un cambio.
En el próximo tema veremos opciones útiles de pytest desde la terminal para controlar mejor la salida y el comportamiento de la ejecución.