En el tema anterior seleccionamos pruebas por archivo, carpeta, nombre y expresión. Ahora agregaremos una forma más explícita de clasificación: los marcadores de pytest.
Los marcadores permiten etiquetar pruebas como lento, regresion, critica, config u otras categorías propias del proyecto. Luego podemos ejecutar o excluir grupos completos.
Un marcador es una etiqueta que se aplica a una prueba. Esa etiqueta no cambia la lógica de la prueba, pero permite clasificarla y seleccionarla.
Ejemplo:
import pytest
@pytest.mark.critica
def test_calcular_total_con_varios_productos_devuelve_suma_total():
assert True
En este caso, la prueba queda marcada como critica.
Los marcadores ayudan a responder preguntas como:
La clasificación permite ejecutar una parte de la suite por intención, no solo por archivo o nombre.
Antes de usarlos, conviene declararlos en pytest.ini:
[pytest]
testpaths = tests
python_files = test_*.py
python_functions = test_*
addopts = -v --strict-markers --tb=short
markers =
lento: pruebas que tardan más tiempo en ejecutarse
regresion: pruebas importantes para detectar regresiones
config: pruebas relacionadas con configuración del proyecto
critica: pruebas indispensables para validar el comportamiento principal
carrito: pruebas relacionadas con el carrito de compras
texto: pruebas relacionadas con normalización y manejo de textos
La opción --strict-markers hace que pytest avise con error si usamos un marcador no declarado.
Modifica tests/test_carrito.py para marcar las pruebas del carrito:
import pytest
from app.carrito import calcular_total, carrito_esta_vacio
@pytest.mark.carrito
@pytest.mark.critica
def test_calcular_total_con_un_producto_devuelve_precio_por_cantidad():
productos = [{"precio": 100, "cantidad": 2}]
assert calcular_total(productos) == 200
@pytest.mark.carrito
@pytest.mark.regresion
def test_calcular_total_con_varios_productos_devuelve_suma_total():
productos = [
{"precio": 100, "cantidad": 2},
{"precio": 50, "cantidad": 3},
]
assert calcular_total(productos) == 350
Una prueba puede tener más de un marcador.
Para ejecutar solo pruebas del carrito:
python -m pytest -m carrito
Para ejecutar solo pruebas críticas:
python -m pytest -m critica
Para ejecutar solo pruebas de regresión:
python -m pytest -m regresion
También podemos excluir grupos. Por ejemplo, para ejecutar todo menos las pruebas lentas:
python -m pytest -m "not lento"
Este comando es útil cuando queremos una ejecución rápida durante el desarrollo.
Los marcadores se pueden combinar con expresiones:
python -m pytest -m "carrito and critica"
Ejecutar pruebas que sean de carrito o texto:
python -m pytest -m "carrito or texto"
Ejecutar regresión excluyendo lentas:
python -m pytest -m "regresion and not lento"
Si usas clases de prueba, puedes marcar una clase completa:
import pytest
@pytest.mark.carrito
class TestCarrito:
def test_carrito_vacio_devuelve_true(self):
assert True
def test_carrito_con_productos_devuelve_false(self):
assert True
Todas las pruebas dentro de la clase reciben el marcador carrito.
También puedes aplicar un marcador a todo un archivo usando pytestmark:
import pytest
pytestmark = pytest.mark.carrito
Si agregas esa línea en tests/test_carrito.py, todas las pruebas del archivo quedan marcadas como carrito.
Supongamos que una prueba tarda más que las demás. Podemos marcarla como lento:
import time
import pytest
@pytest.mark.lento
def test_proceso_lento_de_ejemplo():
time.sleep(1)
assert True
Luego podemos excluirla durante una ejecución rápida:
python -m pytest -m "not lento"
La opción -k selecciona por nombre o expresión textual. La opción -m selecciona por marcador.
Ejemplo con nombre:
python -m pytest -k carrito
Ejemplo con marcador:
python -m pytest -m carrito
-k depende de cómo se llaman las pruebas. -m depende de una clasificación explícita.
Podemos agregar al script un argumento para elegir marcador:
parser.add_argument("--marcador", help="Ejecuta pruebas con el marcador indicado")
Luego, en construir_comando:
if args.marcador:
comando.extend(["-m", args.marcador])
Con esto podrás ejecutar:
python run_tests.py --marcador critica
python run_tests.py --marcador "regresion and not lento"
Si tu script ya tiene --rapido, puede seguir usando el marcador lento:
if args.rapido:
comando.extend(["-m", "not lento"])
Esto hace que el comando:
python run_tests.py --rapido
ejecute todo excepto las pruebas marcadas como lentas.
Los marcadores son útiles, pero no conviene crear una etiqueta para cada detalle. Una suite con demasiados marcadores se vuelve difícil de entender.
Buenas categorías iniciales pueden ser:
critica: pruebas indispensables.regresion: pruebas importantes para evitar errores repetidos.lento: pruebas que no deben ejecutarse siempre.config: pruebas de configuración.carrito o texto.pytest permite listar los marcadores registrados:
python -m pytest --markers
Este comando muestra marcadores propios y marcadores incorporados de pytest. Es útil para revisar si la documentación de pytest.ini quedó clara.
Agrega una sección al README.md:
## Marcadores de pruebas
- critica: pruebas indispensables para validar el comportamiento principal.
- regresion: pruebas importantes para detectar regresiones.
- lento: pruebas que tardan más tiempo en ejecutarse.
- config: pruebas relacionadas con configuración.
- carrito: pruebas relacionadas con el carrito de compras.
- texto: pruebas relacionadas con normalización y manejo de textos.
Ejecutar pruebas críticas:
python -m pytest -m critica
Ejecutar todo excepto pruebas lentas:
python -m pytest -m "not lento"
pytest.ini.and, or o not.-k con -m: recuerda que -k busca por nombre y -m por marcador.Clasifica las pruebas creadas hasta ahora:
test_config.py como config.test_carrito.py como carrito.critica.lento.Luego ejecuta:
python -m pytest -m config
python -m pytest -m critica
python -m pytest -m "not lento"
Ejemplo en tests/test_config.py:
import pytest
from app.config import obtener_ambiente
@pytest.mark.config
def test_config_obtener_ambiente_devuelve_local():
assert obtener_ambiente() == "local"
Ejemplo en tests/test_carrito.py:
import pytest
from app.carrito import calcular_total
@pytest.mark.carrito
@pytest.mark.critica
def test_calcular_total_con_varios_productos_devuelve_suma_total():
productos = [
{"precio": 100, "cantidad": 2},
{"precio": 50, "cantidad": 3},
]
assert calcular_total(productos) == 350
Antes de continuar con el próximo tema, verifica lo siguiente:
pytest.ini.--strict-markers está activo en addopts.@pytest.mark.nombre.python -m pytest -m marcador.python -m pytest -m "not lento".run_tests.py puede usar marcadores si agregaste --marcador.En este tema usamos marcadores de pytest para clasificar pruebas automatizadas. Esto permite ejecutar grupos por intención: críticas, lentas, de regresión, de configuración o de un área funcional.
Los marcadores serán la base del próximo tema, donde separaremos pruebas rápidas, lentas, críticas y de regresión con criterios más claros.