Pruebas de integracion de API: estrategias, herramientas y mejores practicas
Introduccion
Las pruebas unitarias verifican funciones individuales. Las pruebas de API verifican endpoints individuales. Pero ninguna le dice si sus servicios realmente funcionan juntos. Ese es el trabajo de las pruebas de integracion.
Las pruebas de integracion de API validan que multiples servicios, bases de datos y sistemas externos se comuniquen correctamente a traves de sus interfaces de API. En una arquitectura de microservicios donde docenas de servicios dependen entre si, las pruebas de integracion son la red de seguridad que detecta contratos desajustados, fallos de red y problemas de serializacion de datos.
Esta guia cubre las estrategias, herramientas, ejemplos de codigo y mejores practicas que necesita para construir pruebas de integracion de API confiables, desde escenarios simples de dos servicios hasta flujos de trabajo complejos de multiples servicios.
Que son las pruebas de integracion de API?
Las pruebas de integracion de API verifican que los sistemas conectados funcionen correctamente juntos a traves de sus interfaces de API. A diferencia de las pruebas unitarias (que prueban el codigo de forma aislada) o las pruebas de extremo a extremo (que prueban el sistema completo a traves de la interfaz de usuario), las pruebas de integracion se enfocan en los limites entre servicios.
Que validan las pruebas de integracion
- Los datos fluyen correctamente entre servicios (el Servicio A envia datos que el Servicio B puede procesar)
- Se respetan los contratos (la API devuelve los campos y tipos que el consumidor espera)
- El manejo de errores funciona a traves de los limites de servicio (el Servicio A maneja correctamente los errores del Servicio B)
- La autenticacion se propaga correctamente a traves de la cadena de servicios
- Las interacciones con la base de datos funcionan correctamente (consultas, transacciones, migraciones)
- Las APIs externas se comportan como se espera (pasarelas de pago, servicios de correo electronico, datos de terceros)
Pruebas de integracion frente a otros tipos de pruebas
| Tipo de prueba | Alcance | Velocidad | Dependencias | Detecta |
|---|---|---|---|---|
| Pruebas unitarias | Funcion/clase individual | Rapida (ms) | Simuladas | Errores de logica |
| Pruebas de API | Endpoint individual | Rapida (ms-s) | Frecuentemente simuladas | Violaciones de contrato de API |
| Pruebas de integracion | Multiples servicios | Media (s) | Reales o en contenedores | Desajustes de interfaz |
| Pruebas E2E | Sistema completo + UI | Lenta (min) | Todas reales | Errores en flujos de usuario |
Estrategias de pruebas de integracion de API
Estrategia 1: Pruebas de integracion Big Bang
Conecte todos los servicios a la vez y pruebe el sistema completo. Simple de entender pero dificil de depurar cuando las pruebas fallan, ya que no sabe que servicio causo el fallo.
Ideal para: Sistemas pequenos con pocos servicios.
Estrategia 2: Pruebas de integracion incremental
Agregue y pruebe servicios uno a la vez. Comience con el servicio principal y luego agregue servicios conectados de forma incremental.
Top-down: Comience con el API gateway y simule los servicios intermedios, luego reemplace las simulaciones con servicios reales uno por uno.
Bottom-up: Comience con los servicios de nivel mas bajo (base de datos, cache) y construya hacia arriba.
Sandwich: Combine top-down y bottom-up, encontrandose en el medio.
Ideal para: Sistemas medianos a grandes donde necesita aislar los fallos.
Estrategia 3: Pruebas de contrato
Defina contratos entre consumidor y proveedor, luego verifique cada lado de forma independiente. Este es el enfoque mas escalable para los microservicios.
Ideal para: Arquitecturas de microservicios con muchas dependencias entre servicios.
Pruebas de integracion de API en la practica con codigo
JavaScript: prueba de integracion de servicios con Supertest
// tests/integration/orders.test.js const request = require('supertest'); const app = require('../../src/app'); const db = require('../../src/db');describe('Orders API Integration', () => { let userId; let productId;
beforeAll(async () => { // Seed database with test data await db.migrate.latest(); const user = await db('users').insert({ name: 'Test User', email: 'test@example.com' }).returning('id'); userId = user[0].id;
const product = await db('products').insert({ name: 'Widget', price: 29.99, stock: 100 }).returning('id'); productId = product[0].id;});
afterAll(async () => { await db('orders').del(); await db('products').del(); await db('users').del(); await db.destroy(); });
test('Creating an order updates product stock', async () => { // Create order via API const orderRes = await request(app) .post('/api/orders') .send({ userId, items: [{ productId, quantity: 3 }] }) .expect(201);
expect(orderRes.body.total).toBe(89.97); // 29.99 * 3 // Verify stock was decremented const productRes = await request(app) .get(`/api/products/${productId}`) .expect(200); expect(productRes.body.stock).toBe(97); // 100 - 3});
test('Order fails when insufficient stock', async () => { const res = await request(app) .post('/api/orders') .send({ userId, items: [{ productId, quantity: 9999 }] }) .expect(400);
expect(res.body.error).toContain('Insufficient stock');});
test('Order creation sends notification to user service', async () => { const orderRes = await request(app) .post('/api/orders') .send({ userId, items: [{ productId, quantity: 1 }] }) .expect(201);
// Verify notification was created const notifRes = await request(app) .get(`/api/users/${userId}/notifications`) .expect(200); const orderNotif = notifRes.body.find( n => n.type === 'order_confirmation' ); expect(orderNotif).toBeDefined(); expect(orderNotif.orderId).toBe(orderRes.body.id);
}); });
Python: pruebas con pytest y Docker
# tests/integration/test_order_flow.py import pytest import requests import timeAPI_URL = "http://localhost:3000/api"
@pytest.fixture(scope="module") def test_user(): """Create a test user and return their data.""" response = requests.post(f"{API_URL}/users", json={ "name": "Integration Test User", "email": "integration@test.com" }) assert response.status_code == 201 yield response.json() # Cleanup requests.delete(f"{API_URL}/users/{response.json()['id']}")
@pytest.fixture(scope="module") def test_product(): """Create a test product.""" response = requests.post(f"{API_URL}/products", json={ "name": "Test Widget", "price": 19.99, "stock": 50 }) assert response.status_code == 201 yield response.json() requests.delete(f"{API_URL}/products/{response.json()['id']}")
class TestOrderIntegration: def test_complete_order_flow(self, test_user, test_product): """Test the full order lifecycle across services.""" # Step 1: Create order order_response = requests.post(f"{API_URL}/orders", json={ "userId": test_user["id"], "items": [{"productId": test_product["id"], "quantity": 2}] }) assert order_response.status_code == 201 order = order_response.json() assert order["total"] == 39.98 # 19.99 * 2
# Step 2: Verify payment was processed payment_response = requests.get( f"{API_URL}/orders/{order['id']}/payment" ) assert payment_response.status_code == 200 assert payment_response.json()["status"] == "completed" # Step 3: Verify inventory updated product_response = requests.get( f"{API_URL}/products/{test_product['id']}" ) assert product_response.status_code == 200 assert product_response.json()["stock"] == 48 # 50 - 2 def test_order_rollback_on_payment_failure(self, test_user, test_product): """Verify stock is restored when payment fails.""" initial_stock = requests.get( f"{API_URL}/products/{test_product['id']}" ).json()["stock"] # Create order with invalid payment method to trigger failure order_response = requests.post(f"{API_URL}/orders", json={ "userId": test_user["id"], "items": [{"productId": test_product["id"], "quantity": 1}], "paymentMethod": "invalid_card" }) assert order_response.status_code == 400 # Verify stock was not decremented current_stock = requests.get( f"{API_URL}/products/{test_product['id']}" ).json()["stock"] assert current_stock == initial_stock
Pruebas de contrato con Pact
Las pruebas de contrato son el enfoque mas efectivo para probar las integraciones de API en microservicios. El consumidor define lo que espera del proveedor y ambos lados verifican de forma independiente.
Prueba del lado del consumidor (JavaScript)
// consumer/tests/userServiceClient.pact.test.js const { PactV3 } = require('@pact-foundation/pact'); const { UserServiceClient } = require('../src/userServiceClient');const provider = new PactV3({ consumer: 'OrderService', provider: 'UserService', });
describe('UserService Client', () => { test('fetches user by ID', async () => { provider .given('a user with ID 1 exists') .uponReceiving('a request for user 1') .withRequest({ method: 'GET', path: '/api/users/1', headers: { Accept: 'application/json' }, }) .willRespondWith({ status: 200, headers: { 'Content-Type': 'application/json' }, body: { id: 1, name: 'John Doe', email: 'john@example.com', }, });
await provider.executeTest(async (mockServer) => { const client = new UserServiceClient(mockServer.url); const user = await client.getUser(1); expect(user.id).toBe(1); expect(user.name).toBe('John Doe'); });
}); });
Verificacion del lado del proveedor
// provider/tests/pactVerification.test.js const { Verifier } = require('@pact-foundation/pact');describe('UserService Provider Verification', () => { test('validates contract with OrderService', async () => { const verifier = new Verifier({ providerBaseUrl: 'http://localhost:3001', pactUrls: ['./pacts/OrderService-UserService.json'], stateHandlers: { 'a user with ID 1 exists': async () => { // Set up the required state in the provider await db('users').insert({ id: 1, name: 'John Doe', email: 'john@example.com', }); }, }, });
await verifier.verifyProvider();
}); });
Uso de Docker para las pruebas de integracion
Las pruebas de integracion necesitan dependencias reales (bases de datos, caches, colas de mensajes). Docker Compose facilita su gestion:
# docker-compose.test.yml version: '3.8' services: api: build: . environment: DATABASE_URL: postgres://test:test@db:5432/testdb REDIS_URL: redis://cache:6379 depends_on: db: condition: service_healthy cache: condition: service_starteddb: image: postgres:16 environment: POSTGRES_DB: testdb POSTGRES_USER: test POSTGRES_PASSWORD: test healthcheck: test: pg_isready -U test interval: 5s retries: 5
cache: image: redis:7-alpine
test-runner: build: context: . dockerfile: Dockerfile.test environment: API_URL: http://api:3000 depends_on: - api command: npm run test:integration
# Run integration tests
docker-compose -f docker-compose.test.yml up --build --abort-on-container-exit
Pruebas de integracion en CI/CD
# GitHub Actions integration tests
name: Integration Tests
on:
push:
branches: [main, develop]
jobs:
integration:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_DB: testdb
POSTGRES_USER: test
POSTGRES_PASSWORD: test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
redis:
image: redis:7-alpine
ports:
- 6379:6379
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run migrate
env:
DATABASE_URL: postgres://test:test@localhost:5432/testdb
- run: npm run test:integration
env:
DATABASE_URL: postgres://test:test@localhost:5432/testdb
REDIS_URL: redis://localhost:6379
Mejores practicas para las pruebas de integracion de API
1. Use dependencias reales donde sea posible
Las pruebas de integracion con dependencias simuladas no son pruebas de integracion, son pruebas unitarias disfrazadas. Use bases de datos reales, caches reales y colas de mensajes reales mediante contenedores Docker.
2. Aisle los datos de prueba
Cada prueba debe crear sus propios datos y limpiarlos despues. Use transacciones de base de datos que hagan rollback despues de cada prueba o trunce las tablas entre ejecuciones de prueba.
3. Pruebe los escenarios de error
No pruebe solo el camino feliz. Pruebe que sucede cuando las dependencias no estan disponibles, devuelven errores o devuelven datos inesperados.
4. Mantenga las pruebas rapidas
Las pruebas de integracion son mas lentas que las unitarias, pero no deben ser lentas. Apunte a menos de 30 segundos para su suite completa de integracion. Use ejecucion en paralelo y configuracion compartida donde sea seguro.
5. Use pruebas de contrato para APIs entre equipos
Cuando diferentes equipos son responsables de distintos servicios, las pruebas de contrato (con Pact o similares) son mas practicas que ejecutar todos los servicios juntos.
6. Combine con otros tipos de pruebas
Las pruebas de integracion complementan las pruebas de REST API, las pruebas de carga y las pruebas de seguridad. Use Qodex.ai para generar automaticamente pruebas funcionales y de seguridad, luego agregue pruebas de integracion para los flujos de trabajo entre servicios.
Para una vision general completa de las herramientas de prueba, consulte nuestra comparacion de herramientas de prueba de API.
Preguntas frecuentes
Cual es la diferencia entre las pruebas de API y las pruebas de integracion de API?
Las pruebas de API validan un endpoint de API individual de forma aislada: codigos de estado correctos, cuerpos de respuesta y manejo de errores. Las pruebas de integracion de API validan que multiples servicios funcionen juntos a traves de sus APIs: que los datos fluyan correctamente, que los contratos se respeten y que los errores se propaguen adecuadamente a traves de los limites de servicio.
Las pruebas de API son lo mismo que las pruebas de integracion?
No exactamente. Las pruebas de API pueden realizarse de forma aislada (simulando dependencias), lo que las acerca mas a las pruebas unitarias. Las pruebas de integracion prueban especificamente las interacciones entre servicios reales, bases de datos y sistemas externos. Sin embargo, hay una superposicion significativa y muchos equipos usan pruebas de API como pruebas de integracion cuando las realizan contra dependencias reales.
Como pruebo la integracion de API sin acceso al servicio real?
Use pruebas de contrato con herramientas como Pact. El consumidor define las interacciones esperadas y ambos lados verifican de forma independiente. Tambien puede usar servidores simulados, WireMock o herramientas de virtualizacion de servicios para simular el servicio externo.
Que herramientas son las mejores para las pruebas de integracion de API?
Para JavaScript: Supertest + Jest con Docker. Para Python: pytest + requests con Docker. Para pruebas de contrato: Pact. Para generacion automatizada de pruebas: Qodex.ai. Para pruebas entre servicios: Docker Compose para orquestar todos los servicios.
Como manejo los datos de prueba en las pruebas de integracion?
Use transacciones de base de datos que hagan rollback despues de cada prueba o trunce las tablas entre ejecuciones de prueba. Cree los datos de prueba en los hooks setUp/beforeEach y limpie en tearDown/afterEach. Nunca comparta datos de prueba entre pruebas; cada prueba debe ser independiente.
Deben ejecutarse las pruebas de integracion en CI/CD?
Si. Las pruebas de integracion deben ejecutarse en cada push y pull request. Use Docker Compose o contenedores de servicio de CI/CD (como los servicios de GitHub Actions) para iniciar las dependencias reales. Mantenga la suite rapida enfocandose en las rutas de integracion criticas y ejecutando las pruebas en paralelo.
Discover, Test, & Secure your APIs 10x Faster than before
Auto-discover every endpoint, generate functional & security tests (OWASP Top 10), auto-heal as code changes, and run in CI/CD - no code needed.
Related Blogs





