Atlasingeniería

Code review en la prácticaTests que pasan sin probar nadaTema 4

Esperas mágicas y timeouts sin explicación

Un `esperar 500 milisegundos` en el medio de un test. Funciona en la máquina de quien lo escribió, falla en el pipeline cargado y hace la suite más lenta cada vez que alguien sube el número.

El test fallaba de a ratos, alguien agregó una espera de medio segundo y dejó de fallar. Es la solución más tentadora que existe y tiene tres defectos: no arregla la causa, hace la suite más lenta y vuelve a fallar el día que el pipeline está más cargado.

Y cuando vuelve a fallar, la reacción natural es subir el número.

Por qué la espera fija no funciona

SituaciónCon espera fijaCon espera por condición
La operación tarda menosSe pierde el tiempo restante, en cada corrida y en cada testSigue apenas termina
La máquina está cargadaFalla porque la operación tardó más que el número elegidoEspera lo que haga falta, hasta un límite
La operación nunca ocurreFalla con «se esperaba X» sin decir que nunca pasóFalla con un mensaje que dice qué condición no se cumplió
El costo acumulado es real: cien tests con medio segundo de espera son casi un minuto por corrida.

La diferencia de fondo es qué se está expresando. esperar 500 dice “confío en que en medio segundo ya pasó”. Esperar una condición dice “seguí cuando el botón esté habilitado”, que es lo que realmente se quería.

Qué poner en su lugar

Cuatro reemplazos, según el caso

  1. Esperar a que aparezca o cambie algo observable: un elemento en pantalla, un estado, un valor. Con un límite máximo, que es lo que evita que un test colgado bloquee la suite.
  2. Esperar a la promesa o a la señal real. Si el código expone cuándo terminó, usarlo en vez de adivinar. Muchas veces la espera fija existe porque esa señal no se expuso.
  3. Controlar el tiempo en vez de esperarlo. En tests unitarios con temporizadores, adelantar el reloj simulado: el test corre instantáneo y verifica exactamente lo que quería.
  4. Determinismo en el origen. Reemplazar la llamada real por una respuesta controlada elimina la incertidumbre en lugar de tolerarla.

El test que falla de a ratos

La espera mágica casi siempre es el parche de un test inestable, y esos tests tienen un costo que no se ve en ninguna métrica: enseñan al equipo a reintentar el pipeline sin mirar.

Antes de seguir, predecí

Un test falla una de cada diez corridas. ¿Qué conviene hacer?

Las causas habituales son pocas: estado compartido entre tests, orden de ejecución asumido, datos que no se limpian, y operaciones asíncronas sin sincronizar. Las cuatro se arreglan, y ninguna con una espera.

El mismo error fuera de los tests

El patrón se repite en producción: un sleep antes de leer algo que “ya debería estar”, un reintento con un tiempo fijo, una espera para que “termine de propagarse”.

Todos son la misma apuesta contra el tiempo, y todos fallan el día que el sistema está lento —es decir, el día del incidente—. Lo que corresponde es esperar la condición real: consultar el estado, suscribirse al evento, o reintentar con espera creciente y un límite.

Más a fondo · nivel seniorReintento con espera creciente y algo de azar

Cuando hay que reintentar, la espera fija tiene un problema adicional: si mil clientes fallan a la vez, los mil reintentan al mismo tiempo y golpean juntos al servicio que se está recuperando. La espera creciente separa los intentos, y agregarle una variación aleatoria evita que se sincronicen. Es la diferencia entre ayudar a que el servicio se recupere y sostener la caída.

El test que falla de a ratos, en el log

Buscá en el log

El mismo test pasa en la máquina de todos y falla una de cada diez veces en el pipeline. ¿Qué línea muestra por qué?

debug 5info 4warn 0error 211 de 11

Cómo se espera bien

Cierre

Autoevaluación

¿Lo entendiste?

¿Cuál es el problema de reemplazar una espera fija fallida por una más larga?
Un test falla una de cada diez corridas. ¿Qué es lo más probable?