En el tema anterior ejecutamos la suite completa. Eso es necesario antes de cerrar un cambio, pero durante el desarrollo muchas veces conviene ejecutar solo una parte de la suite.
En este tema veremos cómo seleccionar pruebas por carpeta, archivo, función, nombre parcial y expresión. Esto permite trabajar más rápido sin perder orden.
Seleccionar pruebas es útil cuando estás trabajando sobre una funcionalidad concreta y no necesitas ejecutar toda la suite en cada intento.
Por ejemplo, conviene seleccionar pruebas cuando:
El comando general sigue siendo:
python -m pytest
Este comando debe usarse con frecuencia, especialmente antes de dar por terminado un cambio. La selección de pruebas ayuda durante el trabajo, pero no reemplaza la ejecución completa.
Para ejecutar todas las pruebas dentro de una carpeta:
python -m pytest tests
Si tienes subcarpetas, puedes apuntar a una de ellas:
python -m pytest tests/unit
pytest ejecutará las pruebas detectadas dentro de esa ruta.
Para ejecutar solo un archivo:
python -m pytest tests/test_calculadora.py
Esto es útil cuando estás trabajando sobre un módulo específico y quieres validar sus pruebas rápidamente.
pytest permite ejecutar una prueba exacta usando el archivo y el nombre de la función separados por :::
python -m pytest tests/test_calculadora.py::test_sumar_devuelve_la_suma_de_dos_numeros
Esta forma se llama node id. Es una identificación precisa de una prueba.
Si no recuerdas el nombre exacto de una prueba, puedes listar las pruebas sin ejecutarlas:
python -m pytest --collect-only
pytest mostrará las pruebas detectadas. Eso ayuda a copiar el nombre correcto para usarlo luego con ::.
La opción -k permite seleccionar pruebas por una palabra incluida en el nombre:
python -m pytest -k calculadora
También puedes buscar por comportamiento:
python -m pytest -k descuento
Esto funciona mejor cuando las pruebas tienen nombres descriptivos.
Con -k puedes usar expresiones:
python -m pytest -k "usuario and invalido"
También puedes excluir palabras:
python -m pytest -k "usuario and not invalido"
Y combinar alternativas:
python -m pytest -k "usuario or cupon"
Crea el archivo app/carrito.py:
def calcular_total(productos):
return sum(producto["precio"] * producto["cantidad"] for producto in productos)
def carrito_esta_vacio(productos):
return len(productos) == 0
Luego crea tests/test_carrito.py:
from app.carrito import calcular_total, carrito_esta_vacio
def test_calcular_total_con_un_producto_devuelve_precio_por_cantidad():
productos = [{"precio": 100, "cantidad": 2}]
assert calcular_total(productos) == 200
def test_calcular_total_con_varios_productos_devuelve_suma_total():
productos = [
{"precio": 100, "cantidad": 2},
{"precio": 50, "cantidad": 3},
]
assert calcular_total(productos) == 350
def test_carrito_esta_vacio_con_lista_vacia_devuelve_true():
assert carrito_esta_vacio([]) is True
def test_carrito_esta_vacio_con_productos_devuelve_false():
assert carrito_esta_vacio([{"precio": 100, "cantidad": 1}]) is False
Ejecuta el archivo completo:
python -m pytest tests/test_carrito.py
Ejecuta solo pruebas que contengan total en el nombre:
python -m pytest tests/test_carrito.py -k total
Ejecuta solo pruebas relacionadas con carrito vacío:
python -m pytest tests/test_carrito.py -k vacio
Puedes combinar selección con otras opciones:
python -m pytest tests/test_carrito.py -k total -x
Este comando ejecuta solo pruebas del archivo que coinciden con total y se detiene en la primera falla.
También puedes agregar -v para ver cada prueba seleccionada:
python -m pytest tests/test_carrito.py -k total -v
Si -v ya está en pytest.ini, no necesitas repetirlo. Aun así, puede aparecer en comandos de otros proyectos.
Podemos mejorar run_tests.py para aceptar una expresión de búsqueda. Agrega este argumento:
parser.add_argument("--buscar", help="Ejecuta pruebas cuyo nombre coincide con la expresión indicada")
Luego, en construir_comando:
if args.buscar:
comando.extend(["-k", args.buscar])
Así podrás ejecutar:
python run_tests.py --buscar carrito
También podemos permitir que el script reciba una ruta opcional:
parser.add_argument("ruta", nargs="?", default=None, help="Archivo o carpeta de pruebas")
Y en construir_comando:
if args.ruta:
comando.append(args.ruta)
Con esto podrás ejecutar:
python run_tests.py tests/test_carrito.py
python run_tests.py tests/test_carrito.py --buscar total
Cuando uses un argumento posicional como ruta, conviene escribir primero la ruta y luego las opciones:
python run_tests.py tests/test_carrito.py --buscar total
Esto mejora la lectura del comando, aunque argparse puede aceptar distintas posiciones en muchos casos.
La parte de lectura de argumentos puede quedar así:
def leer_argumentos():
parser = argparse.ArgumentParser(description="Ejecuta la suite automatizada")
parser.add_argument("ruta", nargs="?", default=None, help="Archivo o carpeta de pruebas")
parser.add_argument("--buscar", help="Ejecuta pruebas cuyo nombre coincide con la expresión indicada")
parser.add_argument("--rapido", action="store_true", help="Excluye pruebas marcadas como lentas")
parser.add_argument("--reporte", action="store_true", help="Genera un reporte HTML")
parser.add_argument("--detener", action="store_true", help="Detiene la ejecución en la primera falla")
return parser.parse_args()
Y la construcción del comando:
def construir_comando(args):
comando = [sys.executable, "-m", "pytest"]
if args.ruta:
comando.append(args.ruta)
if args.buscar:
comando.extend(["-k", args.buscar])
if args.rapido:
comando.extend(["-m", "not lento"])
if args.detener:
comando.append("-x")
if args.reporte:
REPORTS_DIR.mkdir(exist_ok=True)
comando.extend([
"--html=reports/reporte.html",
"--self-contained-html",
])
return comando
Durante el desarrollo, seleccionar pruebas es práctico. Pero antes de cerrar un cambio, conviene ejecutar la suite completa.
Agrega al README.md una sección de selección de pruebas:
## Seleccionar pruebas
Ejecutar un archivo:
python -m pytest tests/test_carrito.py
Ejecutar una prueba exacta:
python -m pytest tests/test_carrito.py::test_calcular_total_con_un_producto_devuelve_precio_por_cantidad
Buscar por nombre:
python -m pytest -k carrito
Buscar por expresión:
python -m pytest -k "usuario and invalido"
-k.python -m pytest --collect-only.Usando las pruebas de test_carrito.py, ejecuta estos comandos y observa qué pruebas se seleccionan:
python -m pytest tests/test_carrito.py
python -m pytest tests/test_carrito.py -k total
python -m pytest tests/test_carrito.py -k "vacio and true"
python -m pytest --collect-only
Luego agrega al script run_tests.py los argumentos ruta y --buscar si todavía no lo hiciste.
Para ejecutar solo pruebas del carrito que calculan totales:
python -m pytest tests/test_carrito.py -k total
Con el script actualizado:
python run_tests.py tests/test_carrito.py --buscar total
Para ejecutar una prueba exacta:
python -m pytest tests/test_carrito.py::test_calcular_total_con_un_producto_devuelve_precio_por_cantidad
Antes de continuar con el próximo tema, verifica lo siguiente:
python -m pytest.::.-k.--collect-only.run_tests.py puede recibir ruta y expresión de búsqueda.En este tema aprendimos a seleccionar pruebas por carpeta, archivo, función exacta, nombre parcial y expresión. Esta habilidad hace más eficiente el trabajo diario con suites automatizadas.
La selección de pruebas debe usarse para acelerar el desarrollo, pero no debe reemplazar la ejecución completa de la suite. En el próximo tema trabajaremos con marcadores en pytest para clasificar pruebas automatizadas.