Módulo 7 · Pruebas

Lección 35 — Pruebas E2E y de contrato

El flujo completo de compra bajo prueba y contratos que no se rompen.

Publicada
En esta lección
  1. Ejercicio 2 — La compra completa
  2. Ejercicio 3 — El flaky, cazado
  3. Ejercicio 4 — El contrato
  4. Ejercicio 5 — La sala de máquinas
  5. Entrega

La cúpula de la pirámide, pequeña y estable. Sin solutions.md hasta entregar.

  1. 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.
  2. 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.).
  3. 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

  1. Implementa test_compra_feliz completo (buscar → reservar → pagar → confirmar → ticket) con drenar_cola() y asserts sobre el ESTADO final (reserva CONFIRMED, mailbox 1, asientos VENDIDOS).
  2. 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).
  3. 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

  1. 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 a wait_for con deadline 5 s: ¿corre estable 10 veces seguidas? (pytest --count=10 o loop).
  2. El dump de estado: añade al wait_for el 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?
  3. 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

  1. Escribe CONTRATO_FRONT con las 6 interacciones que el front de TicketFlow usa (listado, detalle, reservar, pagar, estado, cancelar) y el test parametrizado que las valida.
  2. Rompe el contrato a propósito: cambia total (int) por total (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?
  3. 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

  1. 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.
  2. El fixture de auth (18): comprador_autenticado que crea usuario, saca access token y lo usa en el client. Sin login "manual" en ningún test.
  3. 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).