Plantilla de Estrategia de Testing de API
Una plantilla para planificar tests de contrato, integración y carga para APIs.
Visión General
Las APIs evolucionan continuamente. Un cambio en un endpoint puede romper consumidores, degradar rendimiento o introducir agujeros de seguridad. Una estrategia de testing por capas detecta estos problemas en diferentes etapas: los tests de contrato previenen cambios rotos, los tests de integración verifican comportamiento, y los tests de carga validan rendimiento bajo presión.
Cuándo Usar
Usa este recurso cuando:
- Diseñas cobertura de testing para una nueva API o microservicio
- Auditas por qué los bugs llegan a producción a pesar de tener unit tests
- Incorporas un pipeline CI/CD que incluye gates de validación de API
- Eliges un enfoque por capas en lugar de tooling más pesado — consulta testing de contratos, mocking de APIs y tests de APIs Express con supertest para el nivel de implementación
Sáltala cuando la API es un único endpoint interno con un solo consumidor — unos pocos tests de integración ganan a una estrategia documentada que nunca vas a revisar. Escribe la estrategia la semana que aparece un segundo consumidor, no el día que creas el repo.
Solución
# Estrategia de Testing de API: <Nombre de la API>
## Alcance
- Endpoints cubiertos: [lista o link al spec OpenAPI]
- Consumidores: [equipos/apps que llaman a esta API]
- Fuera de alcance: [qué no cubre este documento]
## Capa 1 — Tests de Contrato
- Herramienta: [Pact / Spring Cloud Contract / diff de OpenAPI]
- Ubicación del broker: [URL]
- Gate de verificación: [paso de CI que falla el build]
- Responsable: [equipo o persona]
## Capa 2 — Tests de Integración
- Herramienta: [supertest / pytest + httpx / JUnit]
- Entorno: [Testcontainers / docker-compose / staging]
- Casos por endpoint: happy path + [lista de modos de fallo]
- Responsable: [equipo o persona]
## Capa 3 — Tests de Carga
- Herramienta: [k6 / Gatling / JMeter]
- Escenarios: baseline [N RPS], spike [N RPS], soak [duración]
- Presupuestos: [latencia p95, umbrales de tasa de error]
- Frecuencia: [semanal / pre-release]
- Responsable: [equipo o persona]
## Capa 4 — E2E
- Herramienta: [Cypress / Playwright]
- Journeys: [los 3 flujos de usuario principales]
- Frecuencia: [nightly]
## Gates de CI/CD
| Etapa | Corre | Presupuesto |
|-------|-------|-------------|
| Pre-commit | lint + unit | [tiempo] |
| PR build | integración + contrato | [tiempo] |
| Nightly | E2E + baseline de carga | [tiempo] |
| Pre-release | carga completa + soak | [tiempo] |
## Cadencia de Revisión
Última revisión: [fecha] — Próxima revisión: [fecha] — Responsable: [nombre]
Explicación
Los tests de contrato son el ciclo de retroalimentación más rápido para cambios de API porque corren en milisegundos y detectan inconsistencias de schema antes del despliegue. Los tests de integración verifican que tu código funciona con dependencias reales (base de datos, cola de mensajes) sin la sobrecarga de un suite E2E completo. Los tests de carga no se tratan de pasar un número; revelan fugas de recursos, agotamiento de conexiones y misconfiguraciones de autoscaling que solo aparecen bajo carga sostenida.
Escenario Detallado: Estrategia de Testing para una API de Pedidos
API: POST /v1/orders (creación de pedidos)
Equipos: Backend (proveedor), Mobile (consumidor), Web (consumidor)
Capa 1 - Tests de Contrato:
Pact broker: https://pact.example.com
Consumidor Mobile publica contrato:
- Request: POST /v1/orders con body {customer_id, items[]}
- Response: 201 con body {id, status, total_cents}
Proveedor verifica en CI:
$ pact-provider-verifier --provider-base-url=http://localhost:8080 \
--pact-broker-url=https://pact.example.com \
--provider=orders-api --consumer=mobile-app
Gate: si el contrato falla, el PR no se mergea
Capa 2 - Tests de Integración:
Herramienta: Testcontainers + supertest
Casos:
- Happy path: pedido válido retorna 201
- customer_id inexistente: retorna 400
- items vacío: retorna 422
- sin auth token: retorna 401
- idempotency key repetida: retorna 409
BD: PostgreSQL en Testcontainer, datos aislados por test
Capa 3 - Tests de Carga:
Herramienta: k6
Escenarios:
- Baseline: 500 RPS por 10 min, p95 < 300ms
- Spike: 5,000 RPS en 30s, sin errores 5xx
- Soak: 300 RPS por 2h, memoria estable
Frecuencia: semanal + pre-release
Capa 4 - E2E:
Herramienta: Cypress
Journey: login -> agregar al carrito -> checkout -> confirmar
Frecuencia: nightly
Integración CI/CD:
Pre-commit: lint + unit tests (30s)
PR build: integración + contrato (3min)
Nightly: E2E + baseline de carga (20min)
Pre-release: carga completa + soak (45min)
Decidiendo Qué Vive en Cada Capa
El error más común en una estrategia por capas no es una capa ausente — es un test en la capa equivocada. Un check de schema escrito como test de integración corre cien veces más lento que el mismo check como test de contrato, y un journey E2E que ejercita diez aserciones sobre tipos de campos paga precios de E2E por cobertura de contrato. La regla general: si el test solo le importa la forma de los datos, pertenece a la capa de contrato; si le importa el comportamiento con una dependencia real, es de integración; si le importa el sistema bajo carga, le corresponde a k6; y si le importa que un usuario complete un flujo, es E2E.
| Capa | Detecta | Costo | Cuándo corre |
|---|---|---|---|
| Contrato | Cambios rotos de schema | ms | Cada PR |
| Integración | Bugs de comportamiento, wiring de BD/servicios | segundos | Cada PR |
| Carga | Fugas, agotamiento, autoscaling defectuoso | minutos | Nightly / pre-release |
| E2E | Journeys de usuario rotos | minutos | Nightly |
Escribir cada caso en la capa más barata que lo detecta mantiene la suite lo bastante rápida para que los ingenieros la corran de verdad.
Adoptando la Estrategia Incrementalmente
No necesitas las cuatro capas el primer día, y un documento de estrategia que finge que sí se ignora. Empieza donde duele: si los consumidores se quejan de cambios rotos, agrega primero la capa de contrato y gatea los PRs del proveedor con ella. Si los bugs llegan a producción a pesar de unit tests que pasan, el hueco suele ser integración — agrega Testcontainers alrededor de los endpoints que cambiaron el último trimestre. Agrega tests de carga cuando llegue la primera pregunta de capacidad (“¿aguantamos el lanzamiento?”), no antes. Cada capa puede aterrizar en una semana; el documento existe para decir qué capa detecta qué y quién la mantiene, para que los huecos sean decisiones y no accidentes.
Midiendo si la Estrategia Funciona
Tres señales te dicen si la estrategia se gana su mantenimiento. Primero, defects escapados por capa — cuando un bug llega a producción, etiquétalo con la capa que debió detectarlo; un patrón de bugs “debió ser contrato” significa que la capa de contrato está flaca, no que el testing falló. Segundo, latencia del gate — el build del PR debe quedar bajo cinco minutos o los ingenieros empiezan a empujar con --no-verify; vigila la duración mediana de la etapa de contrato + integración y divide o paraleliza cuando se arrastre. Tercero, tasa de flakes — una suite que falla una de cada diez veces sin razón entrena al equipo a clicar “re-run” sin leer, lo que borra silenciosamente el valor del gate. Trackea la tasa de flakes como un SLO; sobre 2% el test flaky se repara o se pone en cuarentena dentro del sprint.
Cómo Adaptar la Plantilla
Recorta lo que no aplica. Una API interna consumida por un único frontend puede saltarse la capa de contrato por completo — su valor es la coordinación multi-consumidor, y con un solo consumidor los tests de integración cubren el mismo terreno más barato. Una API de batch sin tráfico interactivo no necesita escenarios de spike; soak y baseline son los que exponen backlogs de colas. Las APIs GraphQL deben leer “endpoint” como “operación” y testear límites de costo de query donde una API REST testearía comportamiento por path — las capas quedan, cambia la unidad de trabajo. Conserva la tabla de gates de CI/CD corran las capas que corran; es la única parte del documento que tu pipeline realmente enforcea.
Siendo Dueño de la Estrategia
Una estrategia de testing muere igual que una página de estado: nadie es dueño de ella. Asigna cada capa a un nombre, no a un equipo — “tests de contrato: Priya, integración: rotación del on-call” gana a “el equipo de QA”. Cuando un PR queda bloqueado por el gate de contrato y nadie sabe quién puede esquivarlo, el gate se esquiva; cuando un presupuesto de carga rompe y nadie es dueño del número, el presupuesto se edita para pasar. La responsabilidad también decide la cadencia de revisión — trimestral es el default, pero cualquier cambio mayor en la superficie de la API (endpoints nuevos, un consumidor nuevo, una migración de framework) debería disparar una revisión fuera de ciclo, porque el documento describe cobertura que quizá ya no existe.
Mantén el documento lo bastante corto para leerlo de una sentada — dos páginas de decisiones ganan a diez páginas de plantilla que nadie abre. Si una sección nunca cambia entre revisiones, es señal de que es boilerplate; bórrala y conserva las partes sobre las que la gente realmente discute.
Modos de Fallo por Capa
Cada capa falla de una forma característica, y la estrategia debería nombrarlos para que el on-call reconozca lo que está viendo. Los tests de contrato fallan por pacts obsoletos — un consumidor se actualizó hace tres versiones y el broker sigue verificando la vieja. Los tests de integración fallan por deriva de entorno — la imagen del Testcontainer dice PostgreSQL 15 mientras producción corre 16. Los tests de carga fallan por formas de tráfico irreales — RPS uniforme desde una región no dice nada sobre el patrón de ráfaga que tu app móvil produce a las 9 AM. Los tests E2E fallan por tiempo — la suite que tardaba ocho minutos el año pasado tarda treinta ahora, así que corre de noche en vez de por PR, y el ciclo de feedback para el que se compró desaparece en silencio.
La solución para cada uno es el mismo patrón: fija versiones, refleja producción, parametriza desde tráfico real, y presupuesta el runtime de la suite como si costara dinero — porque cuesta.
Trabajando con Dependencias Externas
Toda estrategia choca contra el mismo muro: tus tests necesitan cosas que no controlas. La lista de dependencias pertenece al documento — una tabla corta que mapee cada servicio externo a lo que hace el entorno de test con él. Pasarela de pago: claves sandbox y el servidor mock del proveedor, renovadas cada trimestre porque las credenciales de test expiran. API de clima de terceros: stub de WireMock o MSW grabado de una respuesta en vivo, no un palpito escrito a mano que deriva del schema real. Servicio de email: un sink de captura como Mailhog para que la suite pueda asertar sobre los payloads salientes reales.
La regla que mantiene honesta a la suite: mockea en la frontera de red, nunca dentro de tu propio código. Una respuesta HTTP mockeada ejercita tu serialización, mapeo de errores y lógica de reintento de punta a punta; una interfaz de repositorio mockeada se salta todo eso. Y nunca dejes que la suite dependa de un tercero en vivo para pasar — una caída flaky del proveedor y cada corrida de CI de la empresa se pone roja por razones que nadie de tu equipo causó.
Del Documento al Pipeline
El documento solo cuenta cuando el pipeline lo enforcea, así que haz de la sección de gates la parte más concreta. Escribe los nombres reales de los jobs de CI, no descripciones — verify-pacts, integration-tests, k6-baseline — para que cualquiera que lea el YAML pueda mapearlo de vuelta. Declara la política de fallo en una línea por gate: el fallo de contrato bloquea el merge, sin override; un baseline de carga fallido notifica al canal pero no bloquea (hasta la etapa de pre-release, donde sí); un test flaky que falla dos veces seguidas va a cuarentena y recibe un responsable en un día.
Un gate que nadie puede explicar se convierte en un gate que todos ignoran. Mantén la tabla actualizada — cuando el equipo divida la suite o agregue una etapa, actualiza el documento en el mismo PR. Una estrategia que describe un pipeline que ya no existe es peor que no tener documento: le enseña a los consumidores de la API un flujo que no es real.
Revisando la Estrategia de Otro
Vas a leer más de estos documentos de los que vas a escribir. Al revisar el de un colega, haz cuatro preguntas en orden: ¿Cada capa tiene un responsable con nombre — no un equipo, una persona? ¿Cada gate tiene una política de fallo que alguien puede recitar sin abrir el documento? ¿Hay alguna capa presente por costumbre — una suite E2E para un servicio puro-API, o tests de contrato para un endpoint de un solo consumidor? ¿Y el documento se delata solo — una cadencia de revisión, una línea de “última verificación”, o una etapa del pipeline que todavía referencia una herramienta que el equipo reemplazó hace seis meses? Una estrategia que falla cualquiera de estas se lee como aspiracional y no enforced, y los documentos de test aspiracionales son donde los bugs se esconden entre “alguien debería agregar cobertura” y “nadie lo hizo”. Una estrategia enforced, en cambio, se lee en los detalles — owners con nombre, gates con políticas, y un pipeline que hace exactamente lo que el documento dice — y nada menos que eso en la práctica diaria del equipo completo, no en el papel de la estrategia.
El Lado del Costo del Documento
Una estrategia de testing que nunca menciona costo se revisa el día que finanzas pregunta. La línea cara casi nunca es el tooling — es el runtime: una suite de integración que suma cuatro minutos a cada PR cuesta un día-ingeniero por semana en un equipo de diez. Así que el documento debería cargar un presupuesto aproximado por capa (contrato: bajo un minuto total; integración: bajo cinco; carga: fuera del camino crítico por completo) y un plan de qué pasa cuando una capa lo excede — dividir la suite, paralelizar, o mover los casos más lentos a nightly en vez de dejar que el ciclo de feedback se estire en silencio hasta que la gente deje de esperarlo. Un presupuesto de runtime documentado es también la respuesta cortés cuando alguien propone “solo agregar una capa más”: la pregunta no es si la capa es útil, es si el equipo está dispuesto a pagar su runtime cada día para siempre.
Manteniendo el Documento Vivo
Versiona la estrategia junto al código que describe — un docs/testing-strategy.md en el mismo repo se revisa en el mismo PR que cambia el pipeline, que es como la tabla de gates se mantiene verdadera. Un documento hospedado en una wiki que nadie enlaza desde el repo se pudre en un trimestre. Y cuando salga la siguiente API, no copies la estrategia al por mayor: copia el esqueleto, vuelve a derivar los números desde los consumidores y el tráfico de esa API, y deja que las diferencias de la segunda estrategia te enseñen qué era realmente específico de la primera.
Variantes
| Contexto | Enfoque | Notas |
|---|---|---|
| Serverless | Enfatizar cold start + tests de concurrencia | Localstack o ambiente dev en la nube |
| Event-driven / async | Testear productor + consumidor por separado | Usar bus de mensajes de test, verificar consistencia eventual |
| Monolito legacy | Envolver la API en tests de contrato antes de refactorizar | Pact con el monolito como proveedor |
Lo que funciona
- Tratar tests de contrato fallidos como fallos de build, no como advertencias
- Ejecutar tests de integración contra la misma versión de base de datos usada en producción
- Parametrizar tests de carga con distribuciones reales de requests, no tráfico uniforme
- Etiquetar tests flaky y repararlos dentro de un sprint; no dejarlos acumularse
- Almacenar resultados de tests y líneas base de rendimiento en una base de datos time-series para análisis de tendencias
Errores Comunes
- Testear solo el happy path y asumir que los errores “simplemente funcionan”
- Ejecutar tests de carga en ambientes que difieren de producción
- Usar datos de producción en tests sin anonimizar
- Permitir que los tests dependan de servicios externos fuera de tu control
- Saltear tests de contrato porque “ambos equipos están en la misma sala”
- Escribir un caso en una capa cara que una más barata detectaría
- Dejar que la latencia del gate crezca hasta que los ingenieros lo esquivan
Ejemplos de Tests por Capas
Un test de contrato detecta cambios rotos antes de que la integración corra:
// Contract test — el consumidor verifica que el proveedor honra el pacto
const { Pact } = require('@pact-foundation/pact');
describe('Orders API contract', () => {
it('devuelve un pedido con la forma esperada', async () => {
await provider.addInteraction({
state: 'order 123 exists',
uponReceiving: 'a request for order 123',
withRequest: { method: 'GET', path: '/orders/123' },
willRespondWith: {
status: 200,
body: { id: '123', status: 'shipped', total: expect.any(Number) },
},
});
const res = await api.getOrder('123');
expect(res.body.status).toBe('shipped');
});
});
Un test de integración verifica el comportamiento real contra una dependencia viva — corrélo contra un test container, no contra producción:
// Integration test — supertest contra la app real + DB de test
const request = require('supertest');
const app = require('../app');
describe('POST /orders', () => {
it('crea un pedido y devuelve 201', async () => {
const res = await request(app)
.post('/orders')
.send({ sku: 'ABC', qty: 2 });
expect(res.status).toBe(201);
expect(res.body.id).toBeDefined();
});
});
Y un test de carga te dice dónde rompe el presupuesto — k6 es la herramienta estándar:
// k6 load test — enforcement del presupuesto
import http from 'k6/http';
import { check } from 'k6';
export const options = {
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const res = http.get('https://api.example.com/orders');
check(res, { 'status is 200': (r) => r.status === 200 });
}
Lectura Adicional
- Pact Docs — Cómo funciona Pact — testing de contratos consumer-driven
- Testcontainers — dependencias desechables para tests de integración
- k6 — Guías de testing — tipos de test de carga y thresholds
- Martin Fowler — The Practical Test Pyramid — el modelo de capas canónico
Preguntas frecuentes
¿Cuánta cobertura de test es suficiente?
100% de cobertura de tests de contrato. 80%+ de cobertura de integración para paths críticos. Test de carga para todos los endpoints que reciben > 1% del tráfico. Test E2E para los 3 user journeys principales. No persigas 100% de cobertura de líneas a expensas de aserciones significativas.
¿Debería mockear todos los servicios externos?
Mockea servicios que no poseas o controles (pasarelas de pago, APIs de terceros). Usa instancias reales para servicios que poseas que sean rápidos y confiables (servicio interno de auth, base de datos local). Esto da confianza sin flakiness.
¿Cuál es la diferencia entre tests de contrato e integración?
Los tests de contrato verifican que el schema de request/response coincide con el acuerdo entre consumidor y proveedor. Los tests de integración verifican que tu código de aplicación funciona correctamente con dependencias reales. Los tests de contrato son rápidos y enfocados en schema; los de integración son más lentos y enfocados en comportamiento.
¿Cómo manejo tests de contrato cuando hay múltiples consumidores?
Cada consumidor publica su propio contrato en el Pact Broker. El proveedor verifica todos los contratos en CI. Si un cambio rompe un consumidor pero no otros, el proveedor puede publicar una versión nueva del contrato y notificar al consumidor afectado. Mantén una matriz de compatibilidad: qué consumidor usa qué versión del proveedor.
¿Puedo usar la base de datos de producción para tests de integración?
No. Usa Testcontainers (PostgreSQL en Docker) con la misma versión y configuración que producción. Esto garantiza compatibilidad sin riesgo de mutar datos de producción. Para datos de referencia estables (países, monedas), usa fixtures versionados. Para datos transaccionales, usa factories que generen entidades frescas por test.
Recursos Relacionados
Informe de Pruebas de Carga: Plantilla de Benchmarks
Una plantilla estandarizada para documentar resultados de pruebas de carga: throughput, percentiles de latencia, tasas de error, cuellos de botella con evidencia y acciones — con ejemplo k6 resuelto.
RecipeTesting de Carga de APIs con k6 y Aserciones Basadas en
Como escribir y ejecutar tests de carga con k6 para medir rendimiento de APIs, validar SLOs e identificar cuellos de botella antes del despliegue a produccion
DocPlantilla de Contrato de Microservicios
Una plantilla para definir contratos de servicio y acuerdos de API entre microservicios.
GuideGuía de Pipelines CI/CD: Del Commit a Producción
Guía práctica para construir pipelines CI/CD con GitHub Actions, gates de testing, estrategias de despliegue y procedimientos de rollback.
GuideDesarrollo Guiado por Pruebas (TDD)
Aprende TDD paso a paso: escribe un test que falle, hazlo pasar, refactoriza. Red-Green-Refactor con ejemplos reales en Python, JavaScript y Java.
DocPlantilla de Estrategia de Pruebas
Define tu enfoque de pruebas con esta plantilla de estrategia. Cubre alcance, tipos, herramientas, criterios de entrada/salida, riesgos y cronograma.