Que Es el Testing de Integracion?
El testing de integracion verifica que los componentes individuales del software funcionan correctamente cuando se combinan. Mientras que los unit tests prueban que cada funcion funciona en aislamiento, los tests de integracion prueban que esas funciones funcionan juntas — que los datos fluyen correctamente a traves de los limites entre modulos, que los contratos de API se respetan y que los componentes combinados producen el comportamiento esperado.
Considera un sistema de e-commerce donde el Servicio de Ordenes llama al Servicio de Inventario para verificar stock, luego llama al Servicio de Pagos para cobrar al cliente. Cada servicio podria pasar todos sus unit tests individualmente. Pero que pasa cuando el Servicio de Ordenes envia una solicitud al Servicio de Inventario? Coincide el formato de datos? El Servicio de Inventario retorna la respuesta que espera el Servicio de Ordenes? Funciona el manejo de errores cuando el Servicio de Pagos esta caido?
Estas preguntas son las que responde el testing de integracion.
Por Que los Unit Tests No Son Suficientes
Una analogia clasica: imagina dos equipos construyendo un puente desde lados opuestos de un rio. Cada equipo construye una mitad perfecta. Pero cuando se encuentran en el medio, las mitades no alinean — diferentes alturas, diferentes anchos, diferentes patrones de tornillos.
Cada mitad fue construida correctamente (unit tests pasan), pero no se integran (tests de integracion habrian detectado la incompatibilidad).
En software, las fallas de integracion ocurren porque:
- Incompatibilidad de formatos de datos: El Servicio A envia fechas como “MM/DD/YYYY” pero el Servicio B espera “YYYY-MM-DD”
- Violaciones de contrato de API: La firma del endpoint cambio pero el llamador no se actualizo
- Problemas de timing: El Modulo A asume que el Modulo B responde en menos de 100ms, pero el Modulo B toma 500ms
- Gestion de estado: El Modulo A espera que el Modulo B mantenga estado de sesion, pero el Modulo B es stateless
- Brechas en manejo de errores: El Modulo A no maneja los codigos de error que realmente retorna el Modulo B
Enfoques de Integracion
Hay cuatro estrategias principales para integrar y probar componentes. Cada una tiene ventajas y compromisos distintos.
Se prueba primero] --> TD_B[Stub B] TD_A --> TD_C[Stub C] TD_note["Alto → Bajo"] end subgraph "Bottom-Up" BU_B[Modulo B
Se prueba primero] --> BU_Driver[Driver para A] BU_C[Modulo C
Se prueba primero] --> BU_Driver BU_note["Bajo → Alto"] end subgraph "Sandwich" SW_A[Modulo A
Capa superior] --> SW_B[Modulo B
Capa objetivo] SW_C[Modulo C
Capa inferior] --> SW_B SW_note["Ambas direcciones"] end
Integracion Big Bang
Como funciona: Todos los componentes se desarrollan independientemente, luego se combinan y prueban juntos de una vez.
Ventajas:
- Simple — no se necesitan stubs ni drivers
- Conveniente cuando el sistema es pequeno
Desventajas:
- El aislamiento de defectos es extremadamente dificil
- Los problemas de integracion se descubren tarde
- No es practico para sistemas grandes
Mejor para: Proyectos pequenos con pocos componentes y plazos ajustados.
Integracion Top-Down
Como funciona: Se comienza con el modulo de mas alto nivel y se integra hacia abajo. Los modulos de nivel inferior que no estan listos se reemplazan con stubs.
Proceso:
- Probar el modulo principal con stubs reemplazando sus dependencias
- Reemplazar stubs uno por uno con modulos reales
- Probar despues de cada reemplazo
- Continuar hasta que todos los modulos esten integrados
Ventajas:
- El flujo de control critico se prueba temprano
- Los defectos arquitectonicamente significativos se encuentran temprano
- Se puede demostrar un sistema funcional (parcial) temprano
Desventajas:
- Requiere escribir muchos stubs
- La funcionalidad de nivel inferior se prueba tarde
- Los stubs pueden no simular con precision el comportamiento real
Mejor para: Sistemas donde la arquitectura y el flujo de control de alto nivel son mas criticos.
Integracion Bottom-Up
Como funciona: Se comienza con los modulos de nivel mas bajo y se integra hacia arriba. Los modulos de nivel superior que no estan listos se reemplazan con drivers.
Proceso:
- Probar los modulos de nivel mas bajo usando drivers
- Combinar modulos probados en clusters mas grandes
- Reemplazar drivers con modulos reales de nivel superior
- Continuar hasta que el sistema completo este integrado
Ventajas:
- No se necesitan stubs — los modulos de bajo nivel se prueban con funcionalidad real
- Los defectos en componentes fundamentales se encuentran temprano
- Mas facil observar resultados (la salida de bajo nivel es concreta)
Desventajas:
- El sistema general no es visible hasta las etapas finales
- Requiere escribir drivers
- Los problemas de diseno de alto nivel se descubren tarde
Mejor para: Sistemas donde la base (acceso a datos, utilidades, logica central) es mas critica.
Integracion Sandwich (Hibrida)
Como funciona: Combina los enfoques Top-Down y Bottom-Up. El sistema se divide en tres capas: superior, intermedia (objetivo) e inferior.
Ventajas:
- Combina los beneficios de ambos enfoques
- Sistemas grandes pueden probarse con equipos en paralelo
- Defectos de alto y bajo nivel se encuentran relativamente temprano
Desventajas:
- Mas compleja de planificar y coordinar
- La capa objetivo (intermedia) puede no probarse exhaustivamente
Mejor para: Sistemas grandes con capas claramente definidas donde equipos paralelos trabajan en diferentes componentes.
Integracion de Componentes vs Integracion de Sistemas
Hay dos alcances distintos de testing de integracion:
Testing de Integracion de Componentes verifica interacciones entre componentes dentro del mismo sistema. Ejemplo: probar que el UserService llama correctamente al UserRepository para guardar un registro. Tipicamente lo hacen desarrolladores.
Testing de Integracion de Sistemas verifica interacciones entre diferentes sistemas o aplicaciones. Ejemplo: probar que tu aplicacion se comunica correctamente con una pasarela de pagos externa. Tipicamente lo hace QA.
| Aspecto | Integracion de Componentes | Integracion de Sistemas |
|---|---|---|
| Alcance | Dentro de una aplicacion | Entre aplicaciones/sistemas |
| Quien | Desarrolladores | QA / Equipo de integracion |
| Ambiente | Desarrollo/CI | Staging / Ambiente de integracion |
| Dependencias | Modulos internos | Servicios externos, APIs, bases de datos |
| Velocidad | Rapida (segundos) | Mas lenta (red, sistemas externos) |
Que Probar a Nivel de Integracion
Enfoca los tests de integracion en los limites — los puntos donde los componentes se comunican:
- Contratos de API: El formato de solicitud coincide con lo que espera el receptor?
- Transformaciones de datos: Los datos se convierten correctamente entre componentes?
- Propagacion de errores: Cuando el Servicio B falla, el Servicio A lo maneja adecuadamente?
- Autenticacion/Autorizacion: Los tokens de seguridad fluyen correctamente?
- Interacciones con base de datos: Las consultas retornan datos esperados?
- Colas de mensajes: Los mensajes se publican y consumen en el formato correcto?
- Operaciones de sistema de archivos: Los archivos se escriben y leen correctamente?
Ejercicio: Disena Tests de Integracion para un Sistema de Microservicios
Considera esta arquitectura de microservicios para una plataforma de delivery de comida:
App de Usuario → API Gateway → Servicio de Ordenes → Servicio de Restaurante
→ Servicio de Pagos → Stripe API
→ Servicio de Delivery → Maps API
→ Servicio de Notificaciones → Proveedor Email/SMS
El Servicio de Ordenes:
- Recibe ordenes del API Gateway
- Consulta al Servicio de Restaurante por disponibilidad del menu
- Llama al Servicio de Pagos para cobrar al usuario
- Notifica al Servicio de Delivery para asignar un repartidor
- Activa el Servicio de Notificaciones para enviar confirmacion
Disena tests de integracion para las siguientes interacciones. Para cada una, especifica: que pruebas, comportamiento esperado y escenarios de error.
- Servicio de Ordenes ↔ Servicio de Restaurante
- Servicio de Ordenes ↔ Servicio de Pagos
- Servicio de Ordenes ↔ Servicio de Delivery
- API Gateway ↔ Servicio de Ordenes
Pista
Para cada interaccion, piensa en tres categorias: happy path (todo funciona), manejo de errores (que pasa cuando el otro servicio falla) y validacion de datos (las solicitudes y respuestas estan en formato correcto).Solucion
1. Servicio de Ordenes ↔ Servicio de Restaurante:
- Happy path: Servicio de Ordenes solicita item #42 → Servicio de Restaurante confirma disponible a $12.99 → Servicio de Ordenes usa precio correcto
- Item no disponible: Servicio de Ordenes solicita item agotado → Servicio de Restaurante retorna 404 → Servicio de Ordenes retorna “Item no disponible”
- Restaurante cerrado: Orden a las 3 AM → Servicio de Restaurante retorna estado “cerrado” → Servicio de Ordenes previene la orden
- Validacion de datos: Verificar que IDs, precios y flags de disponibilidad se serializan/deserializan correctamente
- Timeout: Servicio de Restaurante toma >5 segundos → Servicio de Ordenes retorna error de timeout
2. Servicio de Ordenes ↔ Servicio de Pagos:
- Happy path: Total de orden $25.99 → Servicio de Pagos cobra $25.99 via Stripe → retorna ID de transaccion → Servicio de Ordenes almacena el ID
- Pago rechazado: Tarjeta rechazada → Servicio de Pagos retorna razon → Servicio de Ordenes muestra “Pago fallido”
- Verificacion de monto: Verificar que el monto enviado al Servicio de Pagos coincide exactamente con el total (incluyendo impuestos y delivery)
- Idempotencia: Misma orden enviada dos veces → Servicio de Pagos cobra solo una vez
- Flujo de reembolso: Orden cancelada → se llama al endpoint de reembolso → verificar monto correcto
3. Servicio de Ordenes ↔ Servicio de Delivery:
- Happy path: Orden confirmada → Servicio de Delivery recibe direcciones → asigna repartidor mas cercano → retorna tiempo estimado
- Sin repartidores: Servicio de Delivery retorna “sin repartidores” → Servicio de Ordenes notifica retraso
- Validacion de direccion: Direccion invalida → Servicio de Delivery retorna error → Servicio de Ordenes pide correccion
- Formato de datos: Verificar coordenadas GPS, direcciones y ETAs en formatos esperados
4. API Gateway ↔ Servicio de Ordenes:
- Autenticacion: Solicitud sin JWT valido → API Gateway retorna 401, nunca llega al Servicio de Ordenes
- Rate limiting: 100+ solicitudes/minuto del mismo usuario → API Gateway limita, retorna 429
- Ruteo de solicitudes: POST /orders llega al Servicio de Ordenes, rutas invalidas retornan 404
- Transformacion request/response: Verificar que API Gateway reenvía headers, body y query parameters correctamente
Mejores Practicas de Testing de Integracion
Usa Contract Testing para Microservicios
En arquitecturas de microservicios, los servicios los desarrollan diferentes equipos. El contract testing (con herramientas como Pact) asegura que proveedor y consumidor acuerden el contrato de API sin necesitar ambos servicios ejecutandose simultaneamente.
Prueba Interacciones con Base de Datos Correctamente
Los tests de integracion que involucran bases de datos deben:
- Usar una base de datos real (no un fake en memoria) para comportamiento realista
- Ejecutar cada test en una transaccion que hace rollback al terminar
- Usar schemas o contenedores Docker especificos para tests
- Preparar datos de referencia necesarios antes de los tests
Maneja Dependencias de Servicios Externos
Cuando tu sistema depende de APIs externas (Stripe, SendGrid, Google Maps), tienes tres opciones:
- Probar contra ambientes sandbox/staging — mas realista pero lento
- Usar contract tests — verifica que tu codigo cumple la especificacion sin llamar la API
- Usar WireMock o herramientas similares — mock de la API externa con respuestas grabadas
Tips Profesionales
Tip 1: Los tests de integracion deben ser deterministas. Si un test pasa y falla aleatoriamente, erosiona la confianza. Usa datos fijos, controla timing y aisla de otros tests.
Tip 2: Nombra tests de integracion por la interaccion, no el componente. En vez de testOrderService, usa test_order_service_creates_payment_when_order_confirmed.
Tip 3: Mantiene limpios los ambientes de testing. Usa transacciones de base de datos, aislamiento de contenedores o scripts de limpieza. Datos residuales de ejecuciones anteriores son la causa numero uno de tests de integracion inestables.
Conclusiones Clave
- El testing de integracion verifica que los componentes funcionan correctamente al combinarse
- Cuatro enfoques: Big Bang (todos a la vez), Top-Down (alto a bajo), Bottom-Up (bajo a alto), Sandwich (ambos)
- Integracion de componentes prueba dentro de una app; integracion de sistemas entre apps
- Enfoca los tests en limites: contratos API, transformaciones de datos, manejo de errores
- El contract testing es esencial para arquitecturas de microservicios
- Datos deterministicos y ambientes limpios previenen tests inestables