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ón | Con espera fija | Con espera por condición |
|---|---|---|
| La operación tarda menos | Se pierde el tiempo restante, en cada corrida y en cada test | Sigue apenas termina |
| La máquina está cargada | Falla porque la operación tardó más que el número elegido | Espera lo que haga falta, hasta un límite |
| La operación nunca ocurre | Falla con «se esperaba X» sin decir que nunca pasó | Falla con un mensaje que dice qué condición no se cumplió |
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
- 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.
- 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.
- 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.
- 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í
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
La espera fija es de 500 ms y la operación tardó 640. No falló el código: falló el número elegido, que alcanzaba en una máquina descargada y no alcanza cuando el agente comparte CPU con otras tres corridas. Subirlo a 1000 ms hace que la suite entera sea más lenta y que vuelva a fallar el día que el pipeline esté más cargado. La única salida es esperar por la condición —que el elemento exista, que la fila esté en la base— con un límite generoso.
Cómo se espera bien
Cierre
Autoevaluación
¿Lo entendiste?
Práctica