La cúpula de la pirámide, pequeña y estable. Sin solutions.md hasta entregar.
Ejercicio 1 — El catálogo
- Enumera las historias de negocio de TicketFlow y marca las que entran al catálogo E2E (objetivo: ≤ 8 para tu alcance). Para cada una: el flujo HTTP completo y qué dependencia se dobla.
- Las que NO entran: lista 5 casos límite que estuviste tentado a subir a E2E y reasígnalos a su capa real (serializer→unitaria, permisos→integración, etc.).
- Corre
pytest -m e2e --collect-only: el catálogo es medible. ¿Cuántos? ¿Cuánto tardaría a 20 s/test?
Ejercicio 2 — La compra completa
- Implementa
test_compra_felizcompleto (buscar → reservar → pagar → confirmar → ticket) condrenar_cola()y asserts sobre el ESTADO final (reserva CONFIRMED, mailbox 1, asientos VENDIDOS). - La historia trágica: pago declinado → compensación (32). Asserts: estado COMPENSATED, asiento libre de nuevo, email de fallo, webhook NO enviado (el tercero no cobra una venta fallida).
- La historia de la disputa: dos usuarios, mismo asiento, pagos casi simultáneos → UN CONFIRMED, otro compensado con refund. El test de la garantía que vende el negocio.
Ejercicio 3 — El flaky, cazado
- Siembra un flaky a propósito: test que hace
time.sleep(1)y luego aserta el estado de la saga (falla en máquinas lentas). Cámbialo await_forcon deadline 5 s: ¿corre estable 10 veces seguidas? (pytest --count=10o loop). - El dump de estado: añade al
wait_forel dump (estado de la saga, tareas pendientes de la cola eager, últimos 3 eventos del outbox). Rompe el flujo a propósito (el pago no confirma): ¿el dump basta para diagnosticar sin abrir el IDE? - La cuarentena: define
@pytest.mark.flaky(o tu marcador) que en CI re-ejecuta una vez con reporte. La regla: máx 2 tests en cuarentena y issue obligatorio. Escribe la regla en el CONTRIBUTING.md.
Ejercicio 4 — El contrato
- Escribe
CONTRATO_FRONTcon las 6 interacciones que el front de TicketFlow usa (listado, detalle, reservar, pagar, estado, cancelar) y el test parametrizado que las valida. - Rompe el contrato a propósito: cambia
total(int) portotal(objeto {amount, currency}) en la respuesta. ¿Qué test rojo y en cuántos segundos? Ahora cambia el CONTRATO (el consumidor acepta ambos por un sprint, 14: versión dual) — ¿cómo se escribe esa compatibilidad en el test? - El contrato del error (26): añade al contrato las reglas problem+json (type, title, status). Test: el 409 de asiento disputado cumple el contrato de errores.
Ejercicio 5 — La sala de máquinas
- Monta el compose de E2E (app + PG + Redis con healthchecks) y el reset limpio entre tests (truncado + flush Redis DB 15). Mide: ¿cuánto tarda el reset? ¿Y el "reiniciar el mundo" (compose down/up)? La diferencia es la que ahorras ×N tests.
- El fixture de auth (18):
comprador_autenticadoque crea usuario, saca access token y lo usa en el client. Sin login "manual" en ningún test. - La métrica de salud: corre el catálogo 20 veces (o usa los runs del CI si ya existe) y calcula el flaky_rate. ¿< 1%? Si no: ¿qué test va a cuarentena y por qué?
Entrega
Pega el catálogo, los 3 test de historia (feliz/trágica/disputa), el contrato con el rojo del break y la métrica de flakiness. Después: Lección 36 — Pruebas de carga (k6).