Una integración no debe probarse solo cuando todo funciona. Las dependencias pueden fallar, responder tarde, rechazar datos, estar mal configuradas o devolver errores temporales.
El manejo de errores, timeouts y reintentos define cómo se comporta el sistema cuando una colaboración no sale como se esperaba. Probar estos casos es fundamental para evitar estados inconsistentes, operaciones duplicadas y fallas difíciles de diagnosticar.
En este tema veremos cómo diseñar pruebas de integración para situaciones de error y recuperación.
Muchos defectos graves aparecen en caminos alternativos, no en el camino exitoso. Una integración puede funcionar bien cuando la dependencia responde correctamente, pero fallar mal cuando algo sale de lo normal.
Probar errores permite verificar que el sistema:
Conviene distinguir tipos de errores porque no todos deben tratarse igual.
| Tipo | Ejemplo | Tratamiento habitual |
|---|---|---|
| Error de validación | Datos obligatorios faltantes. | Rechazar operación y explicar el problema. |
| Error de negocio | Stock insuficiente. | No continuar y mantener estado coherente. |
| Error temporal | Servicio externo no responde por unos segundos. | Reintentar o dejar pendiente según la regla. |
| Error permanente | Credencial inválida o contrato incompatible. | No reintentar indefinidamente; registrar y reportar. |
| Error inesperado | Respuesta con formato desconocido. | Manejar de forma segura y registrar evidencia. |
Un timeout ocurre cuando una operación tarda más de lo permitido. Es importante porque una aplicación no puede esperar indefinidamente a una dependencia.
Una prueba de integración puede verificar:
Los timeouts deben ser razonables para el ambiente de prueba: ni tan largos que vuelvan lenta la suite, ni tan cortos que generen falsos fallos.
Un reintento es una nueva ejecución de una operación después de una falla. Puede ser útil para errores temporales, pero peligroso si se aplica sin criterio.
Conviene probar:
Reintentar una operación inválida muchas veces solo agrega ruido. Reintentar una operación sensible sin idempotencia puede duplicar efectos.
La idempotencia permite que una operación se repita sin generar efectos duplicados no deseados. Es especialmente importante cuando hay reintentos automáticos.
Una prueba puede verificar que repetir una misma operación:
Si una operación no es idempotente, la estrategia de reintentos debe ser mucho más cuidadosa.
No todos los errores permiten recuperación automática. Diferenciar errores recuperables y no recuperables ayuda a evitar reintentos inútiles.
Ejemplos de errores recuperables:
Ejemplos de errores no recuperables:
Las bases de datos pueden fallar por restricciones, bloqueos, conexiones, timeouts o problemas de transacción.
Una prueba puede verificar qué ocurre cuando:
El resultado esperado debe incluir respuesta adecuada y estado de datos consistente.
Las APIs externas pueden devolver errores esperados o inesperados. La aplicación debe traducir esos errores a decisiones internas claras.
Casos importantes:
Las pruebas deben verificar qué estado queda en nuestra aplicación después de cada respuesta.
En procesos asíncronos, el error puede ocurrir después de que la operación inicial ya respondió. Por eso el diagnóstico y el estado final son especialmente importantes.
Conviene probar:
El sistema debe evitar que un mensaje problemático bloquee indefinidamente todo el procesamiento.
A veces una dependencia falla, pero el sistema puede continuar parcialmente. Esto se llama degradación controlada.
Ejemplos:
Una prueba de integración debe verificar que esta degradación ocurra solo cuando la regla del negocio lo permite.
Cuando una integración falla, el sistema debe dejar evidencia suficiente para investigar. Esto no significa mostrar detalles técnicos al usuario, sino registrar información útil para el equipo.
Conviene registrar:
La prueba puede verificar que ciertos errores queden registrados sin exponer secretos o datos sensibles.
Un error silencioso ocurre cuando algo falla pero el sistema no informa ni registra adecuadamente el problema. Esto es peligroso porque puede dejar datos incorrectos sin señales visibles.
Ejemplos:
Las pruebas de integración deben comprobar que las fallas importantes no desaparezcan sin evidencia.
Supongamos una compra donde la pasarela de pagos no responde a tiempo. Una prueba de integración podría verificar:
| Elemento | Resultado esperado |
|---|---|
| Respuesta de la operación | Indica que el pago no pudo confirmarse o queda pendiente. |
| Orden | No queda como pagada si no hay confirmación. |
| Stock | No se descuenta definitivamente si la compra no fue confirmada. |
| Reintentos | Se ejecutan según la política configurada. |
| Registro | Queda evidencia del timeout y del identificador de operación. |
Si un servicio externo rechaza una solicitud por datos inválidos, reintentar no resolverá el problema. La prueba debería verificar que:
Distinguir errores permanentes de temporales evita comportamientos costosos y confusos.
Al probar manejo de errores, timeouts y reintentos, suelen aparecer errores como:
Antes de confiar en una integración, conviene revisar:
El manejo de errores, timeouts y reintentos define la resiliencia de una integración. Una prueba de integración completa no se limita a confirmar que el camino exitoso funciona; también verifica qué ocurre cuando las dependencias fallan.
Probar estos escenarios ayuda a evitar datos inconsistentes, operaciones duplicadas, errores silenciosos y diagnósticos difíciles.
En el próximo tema veremos dobles de prueba en integración: stubs, fakes y servicios simulados.