13. Estado inicial, limpieza y aislamiento entre pruebas

13.1 Introducción

Una prueba de integración confiable debe poder ejecutarse muchas veces y producir el mismo resultado cuando el código no cambió. Para lograrlo, necesita controlar tres aspectos: el estado inicial, la limpieza y el aislamiento.

Estos aspectos son especialmente importantes en integración porque las pruebas suelen tocar bases de datos, archivos, colas, servicios simulados, cachés y otros recursos compartidos.

Si no controlamos el estado, una prueba puede pasar hoy, fallar mañana y volver a pasar después sin que nadie haya modificado el código. Ese tipo de prueba genera desconfianza y consume tiempo del equipo.

13.2 Qué es el estado inicial

El estado inicial es la situación del sistema antes de ejecutar una prueba. Incluye todos los datos, configuraciones y recursos que pueden influir en el resultado.

Puede incluir:

  • Registros existentes en una base de datos.
  • Archivos presentes en una carpeta.
  • Mensajes pendientes en una cola.
  • Usuarios, permisos y roles cargados.
  • Valores almacenados en caché.
  • Respuestas preparadas en un servicio simulado.
  • Configuración activa para el ambiente de prueba.
Una prueba de integración debe saber en qué estado comienza. Si no conocemos el estado inicial, no podemos interpretar con confianza el resultado.

13.3 Qué significa limpiar

Limpiar significa dejar los recursos usados por una prueba en un estado conocido. Puede hacerse antes de ejecutar la prueba, después de ejecutarla o en ambos momentos.

La limpieza puede consistir en:

  • Eliminar registros creados por la prueba.
  • Revertir una transacción.
  • Vaciar tablas temporales.
  • Borrar archivos generados.
  • Vaciar mensajes de una cola de prueba.
  • Restaurar configuración modificada.
  • Reiniciar servicios simulados.

El objetivo es evitar que una ejecución afecte a la siguiente.

13.4 Qué significa aislar pruebas

Aislar pruebas significa evitar que una prueba dependa del resultado, los datos o el orden de otra prueba. Cada prueba debe preparar lo que necesita y no asumir que otra prueba se ejecutó antes.

Una prueba aislada debería poder:

  • Ejecutarse sola.
  • Ejecutarse junto con toda la suite.
  • Ejecutarse antes o después de otras pruebas.
  • Ejecutarse varias veces sin cambiar su resultado esperado.

El aislamiento no siempre significa usar recursos completamente separados para cada prueba, pero sí controlar las interferencias.

13.5 Señales de falta de aislamiento

Algunas señales indican que las pruebas no están bien aisladas:

  • Una prueba pasa si se ejecuta sola, pero falla dentro de la suite completa.
  • El resultado depende del orden de ejecución.
  • Una prueba falla porque encuentra datos duplicados.
  • Una cola contiene mensajes de pruebas anteriores.
  • Un archivo temporal ya existe cuando la prueba intenta crearlo.
  • Una prueba necesita que otra cree un usuario, producto o configuración.

Cuando aparecen estas señales, el problema no siempre está en la funcionalidad probada. Muchas veces está en la preparación o limpieza del ambiente.

13.6 Limpieza antes o después

La limpieza puede realizarse antes de la prueba, después de la prueba o en ambos momentos. Cada enfoque tiene ventajas y riesgos.

Momento Ventaja Cuidado
Antes de la prueba Garantiza un inicio conocido. Puede ocultar residuos dejados por pruebas anteriores.
Después de la prueba Deja el ambiente limpio para la siguiente prueba. Si la prueba se interrumpe, la limpieza puede no ejecutarse.
Antes y después Aumenta la seguridad del aislamiento. Puede agregar tiempo de ejecución.

En pruebas críticas, limpiar antes y después puede ser razonable, especialmente cuando el ambiente es compartido o puede quedar en un estado inesperado.

13.7 Uso de transacciones

Una estrategia común para pruebas con base de datos es ejecutar la prueba dentro de una transacción y revertirla al finalizar. Esto permite que los cambios no queden persistidos.

Ventajas:

  • La limpieza suele ser rápida.
  • Evita borrar manualmente muchos registros.
  • Reduce residuos entre pruebas.

Cuidados:

  • No siempre sirve si la prueba necesita verificar commits reales.
  • Puede no cubrir procesos que usan otra conexión a la base de datos.
  • No limpia recursos externos, como archivos o colas.

13.8 Recrear la base de datos

Otra estrategia es recrear la base de datos o sus tablas antes de ejecutar una suite. Esto da un punto de partida muy claro.

Puede hacerse aplicando migraciones, cargando datos semilla y luego ejecutando las pruebas.

Ventajas:

  • El esquema queda actualizado.
  • El estado inicial es conocido.
  • Reduce problemas por datos antiguos.

El principal costo es el tiempo de preparación. En proyectos grandes, recrear todo antes de cada prueba puede ser demasiado lento, pero hacerlo antes de la suite puede ser una buena opción.

13.9 Limpieza selectiva

La limpieza selectiva elimina solo los datos creados por una prueba. Para esto conviene que la prueba use identificadores claros o prefijos específicos.

Ejemplos:

  • Eliminar usuarios cuyo correo comience con test-.
  • Borrar pedidos creados con un identificador de ejecución.
  • Eliminar archivos temporales de una carpeta de prueba.
  • Vaciar mensajes con una etiqueta específica.

Esta estrategia puede ser eficiente, pero debe cuidarse para no borrar datos que otras pruebas todavía necesitan.

13.10 Recursos compartidos

Los recursos compartidos son una fuente frecuente de interferencias. Una base de datos, una cola, una carpeta o un servicio simulado pueden ser usados por varias pruebas.

Para reducir problemas, conviene:

  • Separar recursos por ambiente.
  • Usar nombres únicos por suite o prueba.
  • Evitar que pruebas paralelas escriban los mismos registros.
  • Limpiar recursos compartidos antes de comenzar.
  • Registrar qué prueba creó cada dato cuando sea posible.

Cuanto más compartido es un recurso, más importante es controlar su estado.

13.11 Pruebas en paralelo

Ejecutar pruebas en paralelo puede ahorrar tiempo, pero aumenta la necesidad de aislamiento. Dos pruebas que funcionan bien por separado pueden interferirse si usan los mismos datos o recursos al mismo tiempo.

Para ejecutar en paralelo, puede ser necesario:

  • Usar bases de datos separadas por proceso.
  • Generar identificadores únicos.
  • Separar colas o tópicos.
  • Evitar archivos con nombres fijos.
  • No depender de contadores globales sin control.

Si la suite no está preparada para paralelismo, conviene ejecutarla de forma secuencial hasta mejorar el aislamiento.

13.12 Estado en caché

La caché puede afectar pruebas de integración porque guarda resultados de operaciones anteriores. Si una prueba cambia datos pero la aplicación sigue leyendo un valor cacheado, el resultado puede ser incorrecto.

Conviene considerar:

  • Limpiar cachés antes o después de pruebas relevantes.
  • Usar una caché separada para pruebas.
  • Configurar tiempos de expiración pequeños cuando tenga sentido.
  • Verificar que la prueba observe datos actualizados.

La caché puede ocultar errores o producir fallas intermitentes si no se controla.

13.13 Colas y eventos

Las colas de mensajes y los eventos requieren una estrategia especial de limpieza. Un mensaje viejo puede ser consumido por una prueba nueva y generar resultados difíciles de explicar.

Buenas prácticas:

  • Vaciar colas de prueba antes de la ejecución.
  • Usar colas específicas para el ambiente de pruebas.
  • Incluir identificadores de correlación en mensajes.
  • Esperar resultados de forma controlada, no con pausas arbitrarias.
  • Verificar que no queden mensajes pendientes inesperados.

13.14 Archivos temporales

Cuando una integración usa archivos, también debe controlar rutas, nombres y limpieza. Un archivo de una ejecución anterior puede hacer que una prueba falle o pase por una razón equivocada.

Cuidados recomendados:

  • Usar carpetas temporales específicas para pruebas.
  • Crear nombres únicos por ejecución.
  • Borrar archivos al finalizar.
  • No depender de rutas productivas.
  • Verificar contenido y no solo existencia del archivo.

13.15 Ejemplo: aislamiento en una prueba de compra

Supongamos una prueba que confirma una compra y descuenta stock. Para aislarla, podríamos:

Elemento Preparación Limpieza
Usuario Crear usuario propio de la prueba. Eliminarlo al finalizar.
Producto Crear producto con stock conocido. Eliminar producto y movimientos de stock.
Orden No debe existir antes de la prueba. Eliminar la orden creada.
Pago simulado Preparar respuesta aprobada. Reiniciar respuestas del simulador.
Evento Cola vacía antes de comenzar. Vaciar mensajes generados.

13.16 Errores comunes

Al trabajar con estado inicial y limpieza, conviene evitar:

  • Depender de datos creados manualmente.
  • Asumir que las pruebas se ejecutan en cierto orden.
  • No limpiar cuando una prueba falla.
  • Usar nombres fijos para archivos o registros modificables.
  • Compartir usuarios o productos que varias pruebas actualizan.
  • Vaciar tablas completas sin considerar otras pruebas en ejecución.
  • Ignorar cachés, colas o archivos como parte del estado.

13.17 Lista de verificación

Antes de confiar en una prueba de integración, podemos revisar:

  • ¿La prueba prepara explícitamente los datos que necesita?
  • ¿Puede ejecutarse sola?
  • ¿Puede ejecutarse varias veces sin fallar por duplicados?
  • ¿No depende del orden de otras pruebas?
  • ¿Limpia base de datos, archivos, colas y simuladores si los usa?
  • ¿Usa identificadores únicos cuando corresponde?
  • ¿Su resultado no depende de datos residuales?

13.18 Qué debes recordar de este tema

  • El estado inicial debe ser conocido y controlado.
  • La limpieza evita que una ejecución afecte a otra.
  • El aislamiento permite ejecutar pruebas solas, en conjunto y en distinto orden.
  • Las bases de datos, colas, cachés y archivos también forman parte del estado.
  • Las pruebas en paralelo requieren mayor control de recursos compartidos.
  • Una prueba inestable suele indicar problemas de estado, limpieza o aislamiento.

13.19 Conclusión

El estado inicial, la limpieza y el aislamiento son condiciones necesarias para que una suite de integración sea confiable. Sin estos cuidados, las pruebas pueden fallar por residuos, interferencias o dependencias ocultas entre casos.

Una prueba de integración valiosa no solo verifica una colaboración entre componentes; también puede repetirse en un ambiente controlado y explicar con claridad por qué pasó o falló.

En el próximo tema veremos la integración con bases de datos, uno de los casos más comunes y relevantes dentro de las pruebas de integración.