Las pruebas que dependen de una API en vivo son pruebas que fallan por las razones equivocadas. Un servidor de prueba se cae, se activa un límite de tasa de un tercero, un compañero de equipo cambia un registro, y de repente tu suite está en rojo aunque tu código esté bien. Simular la API elimina esa fragilidad. Reemplazas el endpoint real con un sustituto controlado que devuelve exactamente la respuesta que pides, siempre.
Esta guía describe los pasos reales para simular una API para pruebas. Definirás un esquema, generarás respuestas simuladas, apuntarás tu código de prueba a la simulación y cubrirás las rutas de error que un servidor real rara vez produce bajo demanda. Los ejemplos utilizan una pequeña API de gestión de pedidos, pero el flujo de trabajo se aplica a cualquier servicio REST o GraphQL.
Cuando simular la API es la decisión correcta
Simula la API cuando lo que quieres probar es tu propio código, no la red. Las pruebas unitarias y la mayoría de las pruebas de integración caen en esta categoría. Quieres saber que tu cliente analiza correctamente un 200, reintenta en un 503 y muestra un mensaje claro en un 404. Nada de eso requiere un servidor real.
Conserva la API real para las pruebas de contrato y una fina capa de verificaciones de extremo a extremo. Estas existen para confirmar que la simulación sigue coincidiendo con la realidad. Si simulas todo y nunca verificas con el servicio en vivo, tu suite permanece en verde mientras la producción se rompe. La división es, aproximadamente: simulación para velocidad y aislamiento, acceso al elemento real para confirmar el contrato. Para una mirada más profunda sobre dónde encaja cada uno, consulta este desglose de escenarios donde la simulación de API vale la pena y la distinción entre un servidor simulado y un servidor real.
El flujo de trabajo de cinco pasos de un vistazo
Simular una API para pruebas son los mismos cinco movimientos cada vez, independientemente del lenguaje o framework:
- Define el esquema para que la simulación refleje la forma de la respuesta real.
- Genera respuestas simuladas, estáticas o dinámicas, a partir de ese esquema.
- Ejecuta un servidor de simulación que sirva esas respuestas en una URL.
- Apuntala tus pruebas a la simulación haciendo que la URL base sea configurable.
- Prueba las rutas de error que el servidor real no producirá bajo demanda.
El resto de esta guía recorre cada paso con un ejemplo concreto: una pequeña API de gestión de pedidos con un endpoint GET /orders/{id}. Ten en cuenta ese endpoint como hilo conductor.
Paso 1: Define el esquema
Una simulación solo es útil si refleja la forma de la respuesta real. Comienza con un esquema. Si tu API ya tiene un documento OpenAPI, úsalo. Si no, escribe uno para el endpoint bajo prueba. Aquí tienes una definición recortada para GET /orders/{id}:
paths:
/orders/{id}:
get:
parameters:
- name: id
in: path
required: true
schema: { type: string }
responses:
'200':
content:
application/json:
schema:
type: object
properties:
id: { type: string }
status: { type: string, enum: [pending, shipped, delivered] }
total: { type: number }
items: { type: array, items: { type: object } }
'404':
description: Order not found
El esquema cumple dos funciones. Le dice a la simulación qué campos debe devolver, y te da una única fuente de verdad. Cuando el backend cambia el contrato, actualizas el esquema y todas las simulaciones derivadas de él se mantienen precisas. La simulación basada en esquemas es lo que mantiene honestas las pruebas de contrato de API.
Paso 2: Generar respuestas simuladas
Tienes dos formas de producir el cuerpo de la respuesta.
Las respuestas estáticas son JSON fijos. Escribes la carga exacta una vez y la simulación la devuelve sin cambios. Son predecibles y fáciles de verificar, lo que las hace ideales para pruebas unitarias donde quieres un valor conocido.
Las respuestas dinámicas se generan por solicitud. En lugar de codificar "total": 149.99, la simulación llena los campos con valores generados realistas: un UUID para id, un miembro de enum aleatorio para status, una cantidad monetaria plausible para total. Los datos dinámicos detectan errores que una única carga fija oculta, como un analizador que falla con cadenas largas o campos nulos inesperados.
La mayoría de los equipos usan ambos. Cargas estáticas para pruebas con muchas aserciones, generación dinámica para cobertura de estilo fuzzing. Con Apidog, no tienes que escribir ninguno a mano. Apidog lee el esquema y autogenera un endpoint de simulación, haciendo coincidir nombres de campos como email, phone o avatar con el tipo de datos correcto. Apuntas un navegador a la URL de simulación y obtienes una respuesta válida inmediatamente.
Cuando escribas payloads a mano, hazlos realistas. Un pedido de prueba con "total": 0 y una matriz items vacía pasa un analizador ingenuo pero oculta errores. Utiliza valores que se parezcan a la producción: un total de aspecto real, dos o tres artículos, un estado que realmente esté en el enumerado. Cuanto más cerca esté la simulación de los datos de lo que devuelve una solicitud real, más valiosa será tu prueba.
Paso 3: Ejecuta el servidor de simulación
Una respuesta simulada no sirve de nada hasta que algo la sirve. Tienes dos opciones de alojamiento.
Un servidor de simulación local se ejecuta en tu máquina, normalmente en un puerto como localhost:4010. Es rápido, funciona sin conexión y es el predeterminado para las pruebas unitarias y de integración. Herramientas ligeras como Prism lo inician directamente desde un archivo OpenAPI:
prism mock openapi.yaml
# Mock server listening on http://127.0.0.1:4010
Un servidor de simulación en la nube tiene una URL pública. Recurre a uno cuando una aplicación móvil, un ejecutor de CI o un colaborador externo necesite llamar a la simulación sin acceso a tu portátil. Apidog ofrece a cada proyecto una URL de simulación en la nube alojada, para que un compañero de equipo en otra red pueda acceder al mismo endpoint que tú.
Para las ejecuciones de prueba, prefiere lo local. No tiene latencia de red ni estado compartido, por lo que dos compilaciones nunca colisionan. Usa la opción de la nube para demostraciones y pruebas entre dispositivos.
Paso 4: Apunta tus pruebas a la simulación
Ahora conecta el código de prueba a la simulación en lugar de a la producción. El enfoque más limpio es una URL base configurable. Léela desde una variable de entorno para que el mismo archivo de prueba se ejecute contra la simulación localmente y contra la API real en un trabajo de contrato.
// orderClient.test.js
import { getOrder } from './orderClient.js';
const BASE_URL = process.env.API_BASE_URL || 'http://127.0.0.1:4010';
test('parses a shipped order', async () => {
const order = await getOrder('order_8842', BASE_URL);
expect(order.status).toBe('shipped');
expect(typeof order.total).toBe('number');
});
El cliente toma la URL base como argumento; nada en el código de producción sabe que está siendo simulado. En CI, configuras API_BASE_URL con la dirección del mock antes de que se ejecute la suite. Este patrón mantiene la simulación completamente fuera de la lógica de tu aplicación, que es donde debe estar. Si ejecutas pruebas a través de un pipeline, la misma idea se aplica cuando automatizas las pruebas de API en CI/CD.
Paso 5: Prueba las rutas de error
Este es el paso que la mayoría de los equipos omiten, y es el que da más frutos. Un servidor real rara vez devuelve un 500 cuando tú quieres. Un mock devuelve uno bajo demanda.
Configura la simulación para que sirva respuestas de fallo específicas, y luego verifica que tu cliente maneja cada una:
| Escenario | La simulación devuelve | Lo que verificas |
|---|---|---|
| Registro faltante | 404 |
El cliente lanza un error claro de "no encontrado" |
| Fallo del servidor | 500 |
El cliente reintenta, luego muestra un fallback |
| Límite de tasa alcanzado | 429 con Retry-After |
El cliente retrocede la cantidad correcta |
| Respuesta lenta | 200 después de un retraso de 5s |
El cliente agota el tiempo de espera y se recupera |
| Cuerpo mal formado | 200 con JSON defectuoso |
El cliente falla con gracia, sin crashear |
Las reglas de simulación avanzadas de Apidog te permiten devolver diferentes respuestas según la solicitud, de modo que una solicitud para order_404 produce un 404 mientras que cualquier otra ID devuelve un 200 normal. Esto te brinda un único endpoint de simulación que cubre tanto la ruta feliz como los fallos. Combina esto con sólidas aserciones de API y tu suite verificará el comportamiento, no solo los códigos de estado.
Organizando simulaciones en una suite de pruebas creciente
Un único endpoint de simulación es fácil. Cien de ellos, distribuidos en una suite, es donde los equipos pierden el control. Algunos hábitos mantienen el conjunto manejable.
Agrupa las simulaciones por el servicio real al que representan, no por la prueba que las usa. Cuando la API de pago cambia, querrás un solo lugar para actualizar, no veinte archivos de prueba. Nombra los fixtures de simulación según el escenario que representan, como order-shipped o order-rate-limited, para que una prueba fallida se lea claramente. Mantén las definiciones de simulación en el control de versiones junto a las pruebas, ya que una simulación es parte de la prueba y merece la misma revisión.
Resiste la tentación de dar a cada prueba su propia carga personalizada. La mayoría de las pruebas quieren el mismo objeto de pedido realista con un campo cambiado. Define una respuesta base una vez y anula solo el campo bajo prueba. Eso mantiene la suite legible y significa que un cambio de contrato afecta a una definición base en lugar de copias dispersas. La misma disciplina que hace que una suite de pruebas para la automatización de API sea mantenible se aplica directamente a las simulaciones que la respaldan.
Manteniendo la simulación honesta
Una simulación se desvía. El backend añade un campo, renombra total a amount, o cambia un enumerado, y tu simulación sigue devolviendo la forma antigua. Las pruebas pasan; la producción falla. Esta es la forma más común en que la simulación sale mal, y es silenciosa. Nada en tu suite se queja, porque la suite está midiendo la simulación contra sí misma.
Dos hábitos evitan esto. Primero, deriva la simulación del mismo esquema que publica el backend, para que un cambio de contrato actualice ambos a la vez. Una simulación generada a partir de un archivo OpenAPI se regenera cuando ese archivo cambia; una simulación escrita a mano no lo hace. Segundo, ejecuta un pequeño conjunto de pruebas de contrato contra la API real en un horario. Su único trabajo es confirmar que la respuesta en vivo sigue coincidiendo con el esquema que usan tus simulaciones. Cuando fallan, sabes que la simulación está desactualizada antes que los usuarios.
También ayuda revisar las simulaciones durante la revisión del código. Cuando una solicitud de extracción cambia una respuesta de API, el revisor debe verificar que la simulación correspondiente también haya cambiado. Tratar la simulación como parte del contrato, en lugar de una ayuda de prueba desechable, es lo que mantiene una suite simulada confiable durante meses de cambios.
Si quieres un entorno único que contenga el esquema, genere la simulación y ejecute las pruebas contra él, descarga Apidog. Mantiene el diseño, el servidor de simulación y la suite de pruebas sincronizados, de modo que la simulación contra la que pruebas sea siempre el contrato actual. Para opciones más amplias, compara el campo en este resumen de herramientas de simulación de API REST.
Preguntas frecuentes
¿Debería simular la API para cada prueba?
No. Simula para pruebas unitarias y de integración donde estés comprobando tu propio código. Mantén un pequeño conjunto de pruebas de contrato y de extremo a extremo que accedan a la API real, ya que estas confirman que tu simulación aún coincide con la producción. Simularlo todo oculta la desviación del contrato.
¿Cuál es la diferencia entre una respuesta de simulación estática y dinámica?
Una respuesta estática es una carga JSON fija que nunca cambia, lo cual es bueno para aserciones predecibles. Una respuesta dinámica se genera por solicitud con valores realistas, lo que detecta errores que una única carga fija pasaría por alto. La mayoría de los equipos utilizan ambas.
¿Cómo me aseguro de que mi simulación siga siendo precisa?
Genera la simulación a partir del mismo esquema que utiliza el backend, idealmente un documento OpenAPI. Luego, ejecuta pruebas de contrato programadas contra la API real para confirmar que la respuesta en vivo sigue coincidiendo con ese esquema. Si fallan, tu simulación necesita actualización.
¿Puede una simulación simular respuestas lentas o fallidas?
Sí, y esta es una de las razones más sólidas para simular. Puedes configurar una simulación para que devuelva un 500, un 429 con un encabezado Retry-After o un 200 retrasado. Eso te permite verificar la lógica de reintentos y los tiempos de espera que un servidor real saludable nunca activaría bajo demanda.
¿Servidor de simulación local o en la nube para pruebas?
Usa un servidor de simulación local para las ejecuciones de prueba. Es rápido, no tiene latencia de red y evita el estado compartido entre compilaciones. Usa una simulación alojada en la nube cuando un dispositivo móvil, un ejecutor de CI o un colaborador externo necesite acceder a la simulación sin acceso a tu máquina.
