Etiqueta los tests lentos y recupera tu ciclo de trabajo
Si tu suite de tests tarda un minuto, tu ciclo interno está muerto. Dejas de correr los tests en cada guardado, tu agente de código con IA gasta sus iteraciones esperando, y cada cambio pequeño cuesta una pausa de café. La solución no es borrar tests: es etiquetar los lentos para que la corrida por defecto sea rápida.
El problema: unos pocos tests secuestran toda la suite
La mayoría de las suites están desbalanceadas: cientos de tests unitarios que terminan en milisegundos, más un puñado de tests de integración que tocan una base de datos, un contenedor o la red y tardan segundos cada uno. Si corres todo junto, el 5% más lento marca el ritmo del 100% de tus corridas. Encuentra a los culpables con el profiler integrado de pytest:
pytest --durations=10 --durations-min=1.0
Eso imprime los 10 tests más lentos que superan 1 segundo. Esos son tus candidatos a etiquetar.
El mecanismo: markers + -m
Registra los markers una sola vez, para que un error de tipeo no des-etiquete un test en silencio:
# pytest.ini
[pytest]
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
integration: touches a real database, network, or container
addopts = --strict-markers
Decora los tests pesados:
import pytest
@pytest.mark.slow
@pytest.mark.integration
def test_full_checkout_flow(postgres, stripe_sandbox):
...
Y tu corrida diaria queda así:
pytest -m "not slow"
Las expresiones de markers aceptan not, and y or, así que -m "not slow and not integration" o -m "integration or slow" también funcionan. --strict-markers hace que pytest falle con cualquier marker no registrado en lugar de solo advertir — vale la pena activarlo desde el día uno.
Reglas prácticas
| Tipo de test | Tiempo típico | Marker | Dónde corre |
|---|---|---|---|
| Test unitario puro | < 50 ms | ninguno | cada guardado, local + CI |
| Test de componente con fakes | < 500 ms | ninguno | cada guardado, local + CI |
| Toca DB / filesystem / contenedor | 1–10 s | integration | pre-push + CI |
| End-to-end, APIs externas | 10 s + | slow | solo CI |
La meta: el conjunto sin marcar debe completarse en aproximadamente un segundo, para que tú (y tu agente de código) lo corran por reflejo después de cada edición, en lugar de acumular cambios y cruzar los dedos.
Por qué importa más con agentes de IA
Un agente de código itera en un ciclo: edita, corre tests, lee las fallas, edita de nuevo. Si cada ciclo cuesta 60 segundos de tests, un arreglo de 10 iteraciones toma 10 minutos de pura espera — y los agentes corren tests mucho más seguido que los humanos. Dale al agente el comando rápido (pytest -m "not slow") en las instrucciones de tu proyecto, y reserva la suite completa para CI, donde unos minutos de reloj no cuestan nada.
Trucos de usuario avanzado
- Fallas primero.
pytest --lfcorre solo los tests que fallaron la última vez;pytest --ffcorre esos primero y luego el resto. Combinado con-m "not slow", el ciclo de rojo a verde suele bajar de lo que tardas en cambiar de ventana. - CI corre el complemento. Tu job de CI debe correr la suite completa — o explícitamente
pytest -m "slow or integration"en un job paralelo aparte — para que nada etiquetado quede sin ejecutar. Un marker que nunca corre en ningún lado es un test borrado con pasos extra. - Que los markers signifiquen algo.
integrationdebe ser un contrato ("necesita Docker"), no una sensación. Documenta cada marker en la línea de registro — todo lo que sigue a los dos puntos enpytest.inies su descripción, visible conpytest --markers. - Presupuesta el conjunto rápido. Vuelve a correr
--durations=10cada mes. Los tests engordan; un test "unitario" que ganó un fixture de 2 segundos se etiqueta o se arregla.
Recursos
- How to mark test functions with attributes — documentación de pytest
- Working with custom markers — ejemplos de pytest
- Profiling de duración de tests (
--durations) — documentación de uso de pytest - Repetir fallas con
--lf/--ff— documentación del cache de pytest
¿Construyendo una funcionalidad con IA? Yeda AI diseña, audita y entrega sistemas LLM de producción.