Hay un problema que casi nunca aparece en las charlas lindas de automatización.

Todos hablan de Selenium, Playwright, Rest Assured, Appium, Cucumber, reportes, pipelines y arquitectura.

Pero cuando una suite empieza a fallar raro, cuando un test pasa en local y muere en CI, cuando un flujo funciona el lunes y explota el martes sin que nadie haya tocado código, muchas veces el problema no era la herramienta.

Eran los datos.

Los datos de prueba son el enemigo silencioso de la automatización porque no suelen romper todo de golpe. Rompen de a poco. Ensucian la suite, generan falsos negativos, esconden falsos positivos y terminan destruyendo la confianza del equipo.

Y una suite en la que nadie confía es decoración cara.

El test no falla por el botón, falla por el contexto

Cuando un test falla, lo primero que miramos suele ser la UI, el selector, el timeout o el servicio que respondió lento.

Tiene sentido. Es lo visible.

Pero muchas veces el test falló porque arrancó parado sobre un contexto falso.

El usuario no tenía el estado esperado. La cuenta ya estaba usada. El registro fue modificado por otro test. El documento quedó bloqueado por una ejecución anterior. La base tenía basura vieja. El ambiente fue actualizado con datos distintos a los que la suite esperaba.

Entonces el test no está probando comportamiento. Está apostando a que el mundo esté exactamente como lo imaginó.

Eso no es automatización seria.

Eso es una ruleta con assertions.

El dato mágico que todos usan

El primer olor feo aparece cuando una suite depende de datos mágicos.

Ese usuario que “siempre existe”.

Ese cliente con DNI conocido.

Ese producto que “nadie toca”.

Ese registro que tiene justo el estado necesario para ejecutar el flujo.

Al principio parece práctico. Te ahorra setup. Corrés rápido. Escribís menos código.

Hasta que alguien cambia ese dato, otro equipo lo usa, un job nocturno lo actualiza o una ejecución anterior lo deja en otro estado.

Y ahí empieza el clásico circo:

  • “En mi máquina pasa”.
  • “Ayer andaba”.
  • “Volvé a correrlo”.
  • “Seguro fue el ambiente”.

Capaz sí fue el ambiente. Pero si tu test depende de que el ambiente tenga un dato exacto, tu test no está aislado.

Y si no está aislado, no es confiable.

Datos compartidos: el camino rápido hacia el quilombo

El segundo problema es compartir datos entre tests.

Un test crea algo. Otro test lo usa. Un tercero lo modifica. Un cuarto asume que sigue igual.

Eso puede parecer una forma inteligente de ahorrar tiempo, pero en realidad estás armando una cadena de dependencia invisible.

El día que falla el cuarto test, tenés que revisar los tres anteriores para entender qué pasó.

Peor todavía: si ejecutás solo ese cuarto test, falla porque necesita que antes hayan corrido otros.

Un test que no puede correr solo no es un test independiente. Es un capítulo de una novela.

Y las suites automatizadas no deberían depender de leer la novela completa para validar un comportamiento puntual.

El problema no es tener datos, es no gobernarlos

No estoy diciendo que cada test tenga que crear absolutamente todo desde cero pasando por la UI. Eso sería lento, frágil y muchas veces innecesario.

El problema no es usar datos preexistentes.

El problema es usarlos sin contrato.

Si un dato vive en el ambiente y la suite depende de él, entonces ese dato necesita reglas claras:

  • quién lo puede modificar,
  • qué estado debe tener,
  • cómo se restaura,
  • qué tests lo usan,
  • qué pasa si no existe,
  • cómo se detecta que quedó corrupto.

Sin eso, no tenés un fixture. Tenés una esperanza compartida.

Y la esperanza no escala en CI.

Crear datos por UI no siempre es buena idea

Otro error común: pensar que, para ser “realista”, todo dato de prueba debe crearse usando la interfaz.

No.

Crear datos por UI tiene sentido cuando justamente querés validar ese flujo de creación.

Pero si tu test necesita un usuario activo, una cuenta con saldo, una orden pendiente o una entidad en cierto estado para probar otra cosa, crear todo por UI puede convertir un test simple en una peregrinación de veinte pasos.

Y cuanto más largo es el camino, más lugares tenés para fallar por motivos que no pertenecen al objetivo del test.

Ahí conviene pensar en capas.

Podés preparar datos por API cuando el contrato del servicio es estable. Podés usar base de datos cuando el contexto lo permite y el riesgo está controlado. Podés usar fixtures cuando el dato es estático y está gobernado. Podés usar UI cuando el flujo de creación es parte de lo que querés validar.

La pregunta no es “¿cuál forma es más purista?”.

La pregunta es:

¿Cuál forma prepara el contexto con menos ruido y más confianza para este escenario?

El dato de prueba también tiene diseño

Diseñar datos de prueba no es inventar nombres tipo usuarioTest123 y seguir.

Un buen dato de prueba tiene intención.

Tiene un estado conocido. Tiene un propósito. Tiene límites. Tiene una forma de limpieza. Tiene una forma de diagnóstico cuando algo sale mal.

Por ejemplo, si vas a probar que una operación cambia el estado de una entidad, necesitás saber:

  • cuál era el estado inicial,
  • qué acción debería cambiarlo,
  • cuál es el estado final esperado,
  • dónde lo vas a verificar,
  • cómo evitás que otra ejecución toque la misma entidad,
  • cómo limpiás o restaurás el dato después.

Eso es diseño de test.

Lo otro es tirar datos al ambiente y rezar.

Y ya escribí sobre esto en cuando un test automatizado miente: si el test valida algo que no representa el resultado real, te está dando una confianza falsa.

Los datos son parte de la arquitectura de testing

Cuando hablamos de arquitectura de testing, solemos pensar en carpetas, capas, Page Objects, clients, helpers, steps y reporting.

Todo eso importa.

Pero los datos también son arquitectura.

Porque definen si la suite puede correr en paralelo, si puede ejecutarse aislada, si puede repetirse sin romperse y si puede explicar por qué falló.

Una arquitectura linda con datos caóticos sigue siendo una suite caótica.

Podés tener selectors prolijos, steps expresivos y reportes hermosos. Pero si todos los tests dependen del mismo usuario quemado, estás parado sobre arena.

Por eso, cuando diseño una suite, intento separar tres cosas:

  • datos base, que el ambiente necesita para existir,
  • datos de escenario, que cada test prepara para validar un comportamiento,
  • datos generados, que el test crea durante la ejecución y después debe limpiar o dejar identificables.

No siempre se puede hacer perfecto. Pero tener esa separación mental evita muchas decisiones torpes.

Limpieza no significa borrar todo

Cuando se habla de cleanup, algunos imaginan borrar cada registro creado por el test.

A veces sí. A veces no.

En sistemas reales, especialmente en dominios sensibles, borrar puede ser más peligroso que dejar evidencia. Hay auditoría, trazabilidad, procesos batch, integraciones y reglas de negocio que no permiten eliminar alegremente lo que se creó.

Entonces la limpieza puede tomar varias formas:

  • borrar datos temporales cuando el sistema lo permite,
  • dejar los registros en un estado final controlado,
  • marcar datos con un prefijo o identificador de ejecución,
  • usar ambientes efímeros,
  • restaurar snapshots,
  • aislar datos por tenant, usuario, sucursal, cuenta o cualquier frontera del dominio.

Lo importante no es borrar por deporte.

Lo importante es que una ejecución no contamine la siguiente.

Si el test deja el ambiente peor de lo que lo encontró, tarde o temprano la suite te pasa factura.

Base de datos: ni demonio ni salvación

Los datos de prueba también abren otra discusión: cuándo tocar la base.

Ya lo desarrollé en validar contra base de datos: ¿buena práctica o sobreingeniería?, pero vale repetir la idea central.

La base no es mala por existir.

Lo malo es acoplar todos tus tests a detalles internos que no necesitaban conocer.

Si necesitás preparar un estado que solo se puede construir de forma razonable por base, puede tener sentido. Si necesitás verificar persistencia crítica, puede tener sentido. Si lo hacés porque no sabés cómo diseñar el test desde otra capa, probablemente estés comprando deuda.

La base de datos es una herramienta.

No una religión.

Señales de que tus datos están mal diseñados

Hay síntomas bastante claros:

  • el test falla distinto cada vez,
  • necesitás correr casos en un orden específico,
  • no podés ejecutar un test solo,
  • el mismo usuario aparece en veinte escenarios,
  • cada tanto alguien tiene que “arreglar el ambiente”,
  • los errores dicen element not found, pero el problema real era un estado incorrecto,
  • la suite no puede correr en paralelo,
  • los datos de prueba no tienen dueño,
  • nadie sabe qué registros se pueden tocar y cuáles no.

Si ves varias de esas señales, no tenés un problema de herramienta.

Tenés un problema de estrategia de datos.

Y no se arregla metiendo más wait, más retries o más capturas de pantalla.

Eso solo maquilla el incendio.

Qué hago yo en la práctica

No hay receta universal, pero sí hay criterios que ayudan.

Primero, intento que cada test declare qué contexto necesita. Si necesita una cuenta activa, que eso esté claro. Si necesita un usuario sin operaciones previas, que eso esté claro. Si necesita un registro en estado pendiente, que eso esté claro.

Segundo, prefiero generar datos únicos para ejecuciones que pueden repetirse o correr en paralelo. Un timestamp, un UUID corto, un prefijo por suite o un identificador de ejecución pueden evitar choques tontos.

Tercero, separo setup de validación. Preparar el escenario no debería mezclarse con la assertion principal. Si el setup falla, quiero saber que falló el contexto. Si falla la validación, quiero saber que falló el comportamiento.

Cuarto, documento los datos compartidos. Si un dato es importante para varios tests, no puede vivir solo en la cabeza de alguien. Tiene que estar explicado.

Quinto, reviso los datos cuando reviso flakiness. Un test intermitente no se arregla solo mirando screenshots. Hay que mirar estado inicial, estado final, limpieza, ambiente y dependencias externas.

Y sexto, no convierto la suite en una fábrica infinita de basura. Crear datos únicos está bien. Crear basura imposible de rastrear está mal.

Lo que me quedó claro

La automatización no falla solamente por malos selectors, malas esperas o malas herramientas.

Muchas veces falla porque los datos no tienen dueño, no tienen contrato y no tienen diseño.

Y cuando los datos son frágiles, todo lo que construís arriba también es frágil.

Podés tener la mejor arquitectura de testing, pero si cada test depende de que un registro mágico siga vivo en el ambiente, estás jugando a la lotería.

Automatizar bien no es solo escribir código que ejecuta pasos.

Es construir contexto confiable para que esos pasos signifiquen algo.

Porque un test con malos datos no te da calidad.

Te da una ilusión de control.

Y esa ilusión, tarde o temprano, sale cara.