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.

graph TB subgraph "Big Bang" BB_A[Modulo A] --- BB_B[Modulo B] BB_B --- BB_C[Modulo C] BB_A --- BB_C BB_note["Todos a la vez"] end subgraph "Top-Down" TD_A[Modulo A
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:

  1. Probar el modulo principal con stubs reemplazando sus dependencias
  2. Reemplazar stubs uno por uno con modulos reales
  3. Probar despues de cada reemplazo
  4. 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:

  1. Probar los modulos de nivel mas bajo usando drivers
  2. Combinar modulos probados en clusters mas grandes
  3. Reemplazar drivers con modulos reales de nivel superior
  4. 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.

AspectoIntegracion de ComponentesIntegracion de Sistemas
AlcanceDentro de una aplicacionEntre aplicaciones/sistemas
QuienDesarrolladoresQA / Equipo de integracion
AmbienteDesarrollo/CIStaging / Ambiente de integracion
DependenciasModulos internosServicios externos, APIs, bases de datos
VelocidadRapida (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:

  1. Contratos de API: El formato de solicitud coincide con lo que espera el receptor?
  2. Transformaciones de datos: Los datos se convierten correctamente entre componentes?
  3. Propagacion de errores: Cuando el Servicio B falla, el Servicio A lo maneja adecuadamente?
  4. Autenticacion/Autorizacion: Los tokens de seguridad fluyen correctamente?
  5. Interacciones con base de datos: Las consultas retornan datos esperados?
  6. Colas de mensajes: Los mensajes se publican y consumen en el formato correcto?
  7. 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.

  1. Servicio de Ordenes ↔ Servicio de Restaurante
  2. Servicio de Ordenes ↔ Servicio de Pagos
  3. Servicio de Ordenes ↔ Servicio de Delivery
  4. API Gateway ↔ Servicio de Ordenes
PistaPara 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:

  1. Probar contra ambientes sandbox/staging — mas realista pero lento
  2. Usar contract tests — verifica que tu codigo cumple la especificacion sin llamar la API
  3. 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