Integrar componentes de software significa hacer que partes separadas de un sistema colaboren para lograr un comportamiento común. Una aplicación real rara vez está formada por una sola pieza: normalmente contiene módulos, capas, servicios, bases de datos, archivos, APIs, procesos en segundo plano y configuraciones.
Cada componente puede tener una responsabilidad propia, pero el valor para el usuario aparece cuando esas responsabilidades se combinan correctamente. Por ejemplo, registrar una compra puede requerir validación, cálculo, persistencia, actualización de stock y envío de notificaciones.
Las pruebas de integración existen porque entre esas partes aparecen acuerdos, dependencias y riesgos que no siempre se observan al probar unidades aisladas.
En este curso usaremos la palabra componente en un sentido amplio. Un componente es una parte del sistema que cumple una responsabilidad y puede interactuar con otras partes.
Según el tipo de aplicación, un componente puede ser:
Lo importante no es el tamaño exacto del componente, sino que tenga una responsabilidad identificable y una forma de colaborar con otros.
Una idea limitada sería pensar que integrar significa simplemente hacer que dos partes “se llamen”. En realidad, integrar implica mucho más.
Cuando dos componentes se integran, deben coincidir en varios aspectos:
La integración ocurre a través de una interfaz. Una interfaz es el punto de contacto entre componentes. Puede ser una función pública, un método, una ruta HTTP, una consulta, una tabla, un archivo, un mensaje o cualquier mecanismo usado para intercambiar información.
Por ejemplo:
Muchas fallas de integración aparecen cuando una interfaz cambia, está mal documentada o se usa con datos que no respeta.
Detrás de una interfaz existe un contrato. El contrato define qué espera una parte y qué promete la otra. Puede estar escrito en documentación formal o simplemente expresado en el código y en los casos de uso.
Un contrato puede incluir:
Integrar correctamente significa respetar estas expectativas. Si un componente envía “fechaAlta” y otro espera “fecha_alta”, la lógica interna puede estar bien, pero la integración fallará.
Un componente depende de otro cuando necesita su colaboración para completar una tarea. Las dependencias pueden ser internas o externas.
| Tipo de dependencia | Ejemplo | Riesgo posible |
|---|---|---|
| Interna | Un servicio usa un repositorio para guardar datos. | La consulta no coincide con el esquema real. |
| Externa | La aplicación consulta un proveedor de pagos. | El proveedor cambia el formato de respuesta. |
| Infraestructura | Un proceso publica mensajes en una cola. | La cola no existe en el ambiente de pruebas. |
| Datos compartidos | Dos módulos leen y escriben la misma tabla. | Un módulo deja datos en un estado que el otro no espera. |
Las pruebas de integración ayudan a descubrir si esas dependencias están disponibles, configuradas y usadas correctamente.
Muchas aplicaciones se organizan en capas. Una estructura común incluye controlador, servicio y repositorio. Cada capa tiene una responsabilidad distinta:
Integrar estas capas significa verificar que la solicitud pase correctamente de una capa a otra, que los datos se transformen como corresponde y que el resultado final sea coherente.
Por ejemplo, si el controlador recibe un pedido para crear un cliente, el servicio debe validar las reglas necesarias y el repositorio debe guardar el cliente con los valores esperados.
En sistemas más distribuidos, distintos servicios pueden colaborar entre sí. Un servicio de ventas puede consultar un servicio de usuarios, un servicio de stock y un servicio de pagos.
La integración entre servicios agrega riesgos como:
En estos casos, probar la integración no consiste solo en llamar al servicio. También hay que revisar qué ocurre cuando la comunicación falla o cuando la respuesta no es la esperada.
A veces los componentes no se comunican directamente, sino a través de datos compartidos. Por ejemplo, un proceso guarda registros en una tabla y otro proceso los lee más tarde para generar reportes.
Este tipo de integración requiere prestar atención a:
Un error común es que un componente guarde datos válidos para sí mismo, pero insuficientes o ambiguos para el componente que debe consumirlos después.
Una integración puede ser síncrona o asíncrona.
| Tipo | Qué significa | Ejemplo |
|---|---|---|
| Síncrona | Un componente espera una respuesta inmediata de otro. | Consultar una API para validar un pago. |
| Asíncrona | Un componente deja un mensaje o evento para que otro lo procese luego. | Publicar un evento para enviar un correo de confirmación. |
Las integraciones asíncronas suelen requerir cuidados adicionales en las pruebas, porque el resultado puede no aparecer de inmediato. En esos casos, se debe verificar que el mensaje se publique, que el consumidor lo procese y que el estado final sea el esperado.
Muchos componentes trabajan sobre un estado compartido. Ese estado puede estar en una base de datos, memoria, archivos, caché o cola de mensajes. Integrar componentes implica asegurarse de que ese estado se mantenga consistente.
Por ejemplo, si una compra se confirma, no debería quedar una orden como pagada y el stock sin descontar. Si una operación falla, tampoco debería dejar datos intermedios que luego generen errores.
Las pruebas de integración deben observar no solo la respuesta inmediata, sino también el estado que queda después de ejecutar la operación.
Para probar integraciones, necesitamos reconocer dónde termina un componente y dónde empieza otro. Ese límite puede estar definido por una clase, una capa, un servicio, una API, una tabla, un archivo o una cola.
Identificar límites permite decidir:
Un límite claro ayuda a que la prueba tenga un objetivo claro. Si no sabemos qué estamos integrando, tampoco sabremos interpretar bien el resultado.
Supongamos una aplicación que permite registrar una reserva de hotel. Para completar la operación pueden colaborar varios componentes:
Una prueba de integración podría enfocarse solo en controlador, servicio, repositorio y base de datos. Otra podría incluir también el servicio de pagos, o reemplazarlo por una simulación controlada. La decisión depende del objetivo de la prueba.
No todas las integraciones tienen el mismo riesgo. Algunas merecen más atención porque concentran más posibilidades de falla.
Conviene priorizar integraciones donde:
Integrar componentes de software es lograr que responsabilidades separadas se combinen de forma correcta y predecible. Allí aparecen acuerdos entre partes, dependencias, datos compartidos, configuraciones y posibles fallas de coordinación.
Las pruebas de integración ayudan a comprobar que esos acuerdos se cumplan y que el sistema mantenga un comportamiento coherente cuando sus componentes trabajan juntos.
En el próximo tema estudiaremos los errores típicos que aparecen al integrar módulos, para reconocerlos con mayor rapidez y diseñar pruebas que los detecten.