Que Son los Tests Inestables?
Un test inestable (flaky test) es un test que pasa y falla intermitentemente sin ningun cambio de codigo. Ejecutas la suite — pasa. La ejecutas de nuevo con el mismo codigo — un test falla. La ejecutas por tercera vez — pasa. Este comportamiento no determinista destruye la confianza en la suite de tests y desperdicia enormes cantidades de tiempo investigando fallas falsas.
Google reporto que 1.5% de sus tests eran inestables, y esos tests consumian 2-16% de sus recursos de computo completos a traves de reintentos.
Causas Raiz
1. Problemas de Timing y Sincronizacion (Mas Comun)
// MAL — sleep hardcodeado
await page.click('#submit');
await page.waitForTimeout(3000);
// BIEN — esperar condicion
await page.click('#submit');
await expect(page.locator('.result')).toHaveText('Success', { timeout: 10000 });
2. Dependencias de Orden entre Tests
Tests que dependen de que otros tests se ejecuten primero.
3. Estado Mutable Compartido
Tests que modifican estado global sin aislamiento adecuado.
4. Dependencias de Servicios Externos
Tests que llaman servicios externos reales que pueden ser lentos o no estar disponibles.
5. Contention de Recursos
Tests compitiendo por recursos limitados durante ejecucion paralela.
6. Logica Dependiente del Tiempo
Tests que dependen de la hora actual o zona horaria.
Corrigiendo Tests Inestables
Asegurar Aislamiento
@BeforeEach
void isolateTest() { database.beginTransaction(); }
@AfterEach
void cleanupTest() { database.rollbackTransaction(); }
Mockear Servicios Externos
await page.route('**/api/external-service/**', route => {
route.fulfill({ status: 200, body: JSON.stringify({ result: 'mocked' }) });
});
Sistemas de Deteccion
Modo Repeticion en Pipeline de PR
- name: Ejecutar tests nuevos 20 veces
run: |
for i in {1..20}; do
npx playwright test --grep @new
done
Dashboard de Seguimiento
Test: testCheckoutFlow
Ultimas 100 ejecuciones: 96 pass, 4 fail (96% confiabilidad)
Estado: FLAKY (debajo del umbral de 99%)
Ultima falla: TimeoutError en .payment-confirmation
Sistema de Cuarentena
- Marcar: Agregar tag
@Flakyo mover a suite de cuarentena - Aislar: Remover del pipeline CI bloqueante
- Monitorear: Continuar ejecutando en un job separado no bloqueante
- Corregir: Asignar un responsable y establecer deadline
- Restaurar: Una vez corregido y estable por N ejecuciones, mover de vuelta
@Tag("quarantine")
@Flaky(reason = "Timeout intermitente en CI runners lentos", ticket = "BUG-123")
@Test
void testCheckoutWithCoupon() {
// En cuarentena — se ejecuta pero no bloquea deployment
}
Mejores Practicas de Prevencion
- Nunca usar esperas hardcodeadas — siempre usar condiciones explicitas
- Ejecutar tests en orden aleatorio — detecta dependencias de orden
- Repetir tests nuevos — ejecutar 20-50 veces antes de mergear
- Mockear servicios externos — eliminar variabilidad de red
- Usar datos de test unicos — evitar conflictos entre tests paralelos
- Revisar metricas de inestabilidad semanalmente
Ejercicios
Ejercicio 1: Diagnosticar y Corregir
Toma 3 tests intencionalmente inestables y corrige cada uno. Documenta la causa raiz y la solucion.
Ejercicio 2: Construir Sistema de Cuarentena
Crea mecanismo de tag @Quarantine, configura CI para ejecutar tests en cuarentena separadamente, construye script de seguimiento.
Ejercicio 3: Pipeline de Prevencion
Agrega testing en modo repeticion para tests nuevos, configura orden aleatorio, crea dashboard de inestabilidad.