Las pruebas que dependen de una API en vivo fallan por motivos externos a tu código: un servidor de prueba caído, un rate limit de terceros, datos modificados por otro equipo o una respuesta lenta. Simular la API elimina esa fragilidad: sustituyes el endpoint real por un mock controlado que devuelve la respuesta que necesitas, de forma repetible.
En esta guía vas a implementar un flujo práctico para simular una API en pruebas: definir el esquema, generar respuestas mock, levantar un servidor de simulación, apuntar tus tests al mock y cubrir rutas de error difíciles de reproducir con un backend real. Usaremos una API pequeña de gestión de pedidos con el endpoint GET /orders/{id}, pero el patrón aplica a cualquier API REST o GraphQL.
Cuándo simular la API
Simula la API cuando quieres probar tu propio código, no la red ni el backend real.
Casos típicos:
- Tests unitarios de clientes HTTP.
- Tests de integración de frontend/backend contra contratos conocidos.
- Validación de parsing de respuestas.
- Manejo de errores como
404,429,500o timeouts. - Pruebas de retry, fallback y mensajes de error.
Mantén la API real para:
- Pruebas de contrato.
- Una capa pequeña de end-to-end.
- Verificaciones periódicas contra producción o staging.
La división práctica es:
- Mock: velocidad, aislamiento y control.
- API real: confirmar que el contrato sigue siendo válido.
Para profundizar, revisa estos recursos sobre escenarios donde la simulación de API vale la pena y la diferencia entre un servidor simulado y un servidor real.
Flujo de trabajo en cinco pasos
Simular una API para pruebas suele seguir el mismo proceso:
- Define el esquema de la API.
- Genera respuestas simuladas estáticas o dinámicas.
- Ejecuta un servidor de simulación accesible por URL.
- Apunta tus pruebas al mock usando una URL base configurable.
- Prueba rutas de error que el backend real no expone bajo demanda.
El ejemplo base será:
GET /orders/{id}
Paso 1: Define el esquema
Un mock solo es útil si respeta la forma real de la respuesta. Empieza por un contrato. Si ya tienes un documento OpenAPI, úsalo. Si no, define el endpoint que vas a probar.
Ejemplo mínimo 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
Este esquema te da dos beneficios:
- El mock sabe qué campos debe devolver.
- Tus tests tienen una fuente de verdad compartida con el backend.
Cuando el contrato cambia, actualizas el esquema y regeneras las respuestas mock desde ahí. Esa disciplina es clave para mantener confiables las pruebas de contrato de API.
Paso 2: Genera respuestas simuladas
Puedes usar dos tipos de respuestas.
Respuestas estáticas
Son payloads JSON fijos. Úsalas cuando necesitas aserciones exactas.
Ejemplo:
{
"id": "order_8842",
"status": "shipped",
"total": 149.99,
"items": [
{
"sku": "sku_keyboard",
"quantity": 1
},
{
"sku": "sku_mouse",
"quantity": 1
}
]
}
Son ideales para tests como:
expect(order.status).toBe('shipped');
expect(order.total).toBe(149.99);
Respuestas dinámicas
Se generan por solicitud. En lugar de devolver siempre el mismo total, el mock puede producir valores realistas:
- UUIDs para
id. - Un valor válido del enum para
status. - Cantidades monetarias plausibles para
total. - Arrays con tamaños variables.
Esto ayuda a detectar errores que un fixture único puede ocultar, por ejemplo:
- Parsers que fallan con strings largos.
- Campos opcionales ausentes.
- Arrays vacíos.
- Valores nulos inesperados.
La mayoría de equipos combina ambas estrategias:
- Estáticas para tests deterministas.
- Dinámicas para cobertura más amplia.
Con Apidog, puedes generar endpoints mock desde el esquema. Apidog interpreta nombres de campos como email, phone o avatar y devuelve datos acordes al tipo esperado.
Si escribes payloads a mano, evita fixtures demasiado artificiales como:
{
"id": "1",
"status": "pending",
"total": 0,
"items": []
}
Mejor usa datos parecidos a producción:
{
"id": "order_8842",
"status": "shipped",
"total": 149.99,
"items": [
{
"sku": "sku_keyboard",
"name": "Mechanical Keyboard",
"quantity": 1,
"price": 99.99
},
{
"sku": "sku_mouse",
"name": "Wireless Mouse",
"quantity": 1,
"price": 50
}
]
}
Paso 3: Ejecuta el servidor de simulación
Una respuesta mock necesita servirse desde una URL. Tienes dos opciones principales.
Opción A: servidor mock local
Úsalo para tests unitarios e integración local. Es rápido, no depende de red externa y evita estado compartido.
Con Prism, puedes levantar un mock desde un archivo OpenAPI:
prism mock openapi.yaml
# Mock server listening on http://127.0.0.1:4010
Luego puedes probarlo con curl:
curl http://127.0.0.1:4010/orders/order_8842
Opción B: servidor mock en la nube
Úsalo cuando el mock debe ser accesible desde:
- Una app móvil.
- Un runner de CI.
- Un colaborador externo.
- Otro equipo sin acceso a tu máquina.
Apidog ofrece una URL de simulación alojada por proyecto, útil para compartir el mismo endpoint mock entre varias personas o dispositivos.
Para ejecución automatizada de tests, prefiere local cuando sea posible. Para demos, pruebas entre dispositivos o colaboración remota, usa mock en la nube.
Paso 4: Apunta tus pruebas al mock
No hardcodees la URL de producción en tus tests. Haz que la URL base sea configurable.
Ejemplo de cliente:
// orderClient.js
export async function getOrder(id, baseUrl) {
const response = await fetch(`${baseUrl}/orders/${id}`);
if (response.status === 404) {
throw new Error(`Order ${id} not found`);
}
if (!response.ok) {
throw new Error(`Unexpected API error: ${response.status}`);
}
return response.json();
}
Test apuntando al mock:
// 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');
expect(Array.isArray(order.items)).toBe(true);
});
En local:
API_BASE_URL=http://127.0.0.1:4010 npm test
En CI puedes apuntar la misma suite a otro entorno:
API_BASE_URL=https://mock.example.com npm test
El código de producción no necesita saber si está usando un mock o una API real. Solo recibe una URL base. Este mismo patrón aplica cuando automatizas las pruebas de API en CI/CD.
Paso 5: Prueba las rutas de error
Este es el mayor valor de un mock: puedes forzar respuestas que un backend real no produce cuando tú quieres.
Configura escenarios como estos:
| Escenario | La simulación devuelve | Qué verificas |
|---|---|---|
| Registro faltante | 404 |
El cliente lanza un error claro de "no encontrado" |
| Fallo del servidor | 500 |
El cliente reintenta y luego usa un fallback |
| Rate limit |
429 con Retry-After
|
El cliente espera el tiempo correcto |
| Respuesta lenta |
200 después de 5s |
El cliente aplica timeout y se recupera |
| Cuerpo inválido |
200 con JSON defectuoso |
El cliente falla sin crashear |
Ejemplo de test para 404:
test('throws a clear error when order does not exist', async () => {
await expect(getOrder('order_404', BASE_URL))
.rejects
.toThrow('Order order_404 not found');
});
Ejemplo de test para 500 con retry:
test('retries when the API returns 500', async () => {
const order = await getOrderWithRetry('order_retry', BASE_URL, {
retries: 2
});
expect(order.id).toBe('order_retry');
});
Las reglas avanzadas de simulación de Apidog permiten devolver respuestas distintas según la solicitud. Por ejemplo:
-
GET /orders/order_404devuelve404. -
GET /orders/order_timeoutresponde con retraso. -
GET /orders/order_8842devuelve200.
Así puedes cubrir la ruta feliz y los fallos desde un único endpoint mock. Combínalo con buenas aserciones de API para verificar comportamiento, no solo códigos de estado.
Organiza los mocks en una suite creciente
Un mock para un endpoint es fácil. Cien mocks repartidos en una suite se vuelven difíciles de mantener si no hay estructura.
Buenas prácticas:
Agrupa por servicio real
Organiza los mocks según el servicio que representan:
mocks/
orders/
order-shipped.json
order-not-found.json
order-rate-limited.json
payments/
payment-approved.json
payment-declined.json
No los agrupes por test individual. Si cambia la API de pedidos, quieres actualizar una carpeta, no veinte archivos dispersos.
Nombra fixtures por escenario
Usa nombres que expliquen el caso:
order-shipped.json
order-delivered.json
order-not-found.json
order-rate-limited.json
Así, cuando falle un test, el fixture ya comunica la intención.
Versiona los mocks junto a los tests
Los mocks son parte de la prueba. Deben pasar por code review igual que el código de test.
Usa una respuesta base
Evita copiar payloads completos para cada test. Define una respuesta base y cambia solo el campo relevante.
Ejemplo:
const baseOrder = {
id: 'order_8842',
status: 'shipped',
total: 149.99,
items: [
{ sku: 'sku_keyboard', quantity: 1 },
{ sku: 'sku_mouse', quantity: 1 }
]
};
const pendingOrder = {
...baseOrder,
status: 'pending'
};
Este enfoque reduce duplicación y hace que los cambios de contrato sean más fáciles de aplicar. La misma disciplina que mantiene una suite de pruebas para la automatización de API también mantiene sanos tus mocks.
Mantén la simulación alineada con la API real
El riesgo principal de un mock es la deriva del contrato.
Ejemplos:
- El backend renombra
totalaamount. - Se agrega un campo obligatorio.
- Cambia un enum.
- Un campo deja de aceptar
null. - La estructura de
itemscambia.
Si tus mocks no se actualizan, la suite puede seguir en verde mientras producción falla.
Para evitarlo:
1. Genera mocks desde el mismo esquema
Usa el mismo OpenAPI que publica el backend. Si el contrato cambia, el mock debe regenerarse desde esa fuente.
2. Ejecuta pruebas de contrato contra la API real
Mantén una suite pequeña que valide que la API viva sigue respetando el esquema.
Ejemplo de estrategia:
tests/
unit/ -> usan mock local
integration/ -> usan mock local o mock cloud
contract/ -> usan API real de staging
e2e/ -> usan API real con pocos casos críticos
3. Revisa mocks en cada pull request
Si una PR cambia una respuesta de API, debe cambiar también:
- El esquema OpenAPI.
- Los fixtures mock.
- Las pruebas afectadas.
Trata la simulación como parte del contrato, no como un helper temporal.
Si quieres un entorno que concentre esquema, mock server y pruebas, puedes descargar Apidog. También puedes comparar alternativas en esta lista de herramientas de simulación de API REST.
Preguntas frecuentes
¿Debería simular la API para cada prueba?
No. Simula en pruebas unitarias e integración cuando estás validando tu propio código. Mantén un conjunto pequeño de pruebas de contrato y end-to-end contra la API real para confirmar que el mock sigue alineado con producción.
¿Cuál es la diferencia entre una respuesta mock estática y dinámica?
Una respuesta estática es un JSON fijo y predecible. Es útil para aserciones exactas.
Una respuesta dinámica se genera por solicitud con valores realistas. Es útil para descubrir errores que un único fixture no detectaría.
Lo habitual es usar ambas.
¿Cómo aseguro que mi mock siga siendo preciso?
Genera el mock desde el mismo esquema que usa el backend, idealmente OpenAPI. Luego ejecuta pruebas de contrato programadas contra la API real. Si esas pruebas fallan, el contrato o el mock deben actualizarse.
¿Puede un mock simular respuestas lentas o fallidas?
Sí. Puedes configurar respuestas como:
-
500 Internal Server Error. -
429 Too Many RequestsconRetry-After. -
200 OKcon retraso. - JSON mal formado.
- Timeouts.
Esto permite probar lógica de retries, fallback y manejo de errores sin romper un backend real.
¿Servidor mock local o en la nube?
Usa mock local para ejecuciones de test: es rápido, aislado y sin latencia externa.
Usa mock en la nube cuando necesites acceso desde una app móvil, CI remoto, otro equipo o colaboradores externos.
Top comments (0)