Caché en Go: ¿Enemigo de las pruebas? Analizando force retesting

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué Go oculta los resultados de las pruebas? (Y cómo arruina la vida)

\n\n

Imagínese: está escribiendo en Go, ejecuta go test, ve una marca verde... pero algo salió mal. Corrigió un error, vuelve a ejecutar las pruebas, y otra vez luz verde. ¡Pero el error sigue ahí! ¿Le suena familiar? Bienvenido al mundo del almacenamiento en caché de pruebas de Go.

\n\n

Go es un lenguaje que ama la velocidad. Para no ejecutar las mismas pruebas diez veces, el compilador almacena en caché los resultados. Suena conveniente, hasta que se enfrenta a una situación donde el caché de pruebas de Go comienza a trabajar en su contra. Esto afecta especialmente a los desarrolladores que trabajan con pruebas de integración, sistema de archivos o API externas.

\n\n

En este artículo analizaremos dos enfoques para resolver el problema: force retesting (reinicio forzado) y la desactivación completa de la caché de pruebas. Aprenderá cuándo aplicar cada uno y obtendrá ejemplos de código funcionales.

\n\n

Cómo funciona el almacenamiento en caché de pruebas en Go

\n\n

Antes de romperlo, entendamos cómo funciona. Go almacena en caché los resultados de las pruebas basándose en un hash de:

\n
    \n
  • Código fuente (archivos .go)
  • \n
  • Archivos de prueba
  • \n
  • Variables de entorno
  • \n
  • Flags de compilación
  • \n
\n\n

Si nada ha cambiado, Go simplemente muestra el resultado en caché. ¿Rápido? Sí. ¿Peligroso? ¡Y mucho! Imagine que su prueba depende del tiempo, números aleatorios o un servicio externo. La caché dirá: "¡Todo bien!", aunque en realidad la prueba ya habría fallado.

\n\n
// Ejemplo de prueba que será falsamente verde debido a la caché\nfunc TestCurrentTime(t *testing.T) {\n    now := time.Now()\n    if now.Year() != 2024 {\n        t.Errorf("El año debe ser 2024, se obtuvo %d", now.Year())\n    }\n}
\n\n

Ejecute esta prueba una vez: pasará. ¿Corrige el año a 2025 en el código? La caché seguirá mostrando el resultado anterior. Y se preguntará por qué el CI falla, mientras que localmente "funciona".

\n\n

Enfoque 1: Force retesting (reinicio forzado)

\n\n

La forma más popular de combatir la caché es el flag -count=1. Esto es force retesting en su forma más pura. Le dice a Go: "No confíes en la caché, reinicia la prueba desde cero".

\n\n
// Ejecución con reinicio forzado\ngo test -count=1 ./...
\n\n

¿Por qué -count=1 y no -count=0? Porque -count establece el número de ejecuciones de la prueba. 1 es el valor mínimo que desactiva la caché. 0 simplemente no ejecutará nada.

\n\n

Cuándo usar force retesting

\n
    \n
  • Pruebas de integración que acceden a BD o API
  • \n
  • Pruebas con datos aleatorios (fuzz testing, generación de UUID)
  • \n
  • Pruebas que dependen del tiempo (timeouts, fechas)
  • \n
  • Desarrollo local, cuando cambia código con frecuencia
  • \n
\n\n

Ejemplo: prueba de integración con force retesting

\n\n
package db_test\n\nimport (\n    "testing"\n    "time"\n)\n\nfunc TestDatabaseConnection(t *testing.T) {\n    // Esta prueba depende de un servidor en vivo\n    // Sin -count=1 podría mostrar un resultado antiguo\n    db := connectToDatabase()\n    if err := db.Ping(); err != nil {\n        t.Fatalf("No se pudo conectar: %v", err)\n    }\n    \n    // Simulación de retardo temporal\n    time.Sleep(100 * time.Millisecond)\n    if err := db.Query("SELECT 1"); err != nil {\n        t.Errorf("Consulta fallida: %v", err)\n    }\n}
\n\n

Ejecutamos: go test -count=1 -v ./db/. Ahora cada ejecución es honesta. Pero hay un detalle: force retesting no resuelve el problema globalmente. Si olvida el flag, la caché volverá.

\n\n

Enfoque 2: Desactivación completa de la caché de pruebas

\n\n

La segunda opción es radical. Simplemente le dice a Go: "No almacenes nada en caché". Esto se hace mediante la variable de entorno GOCACHE=off o el flag -count=1

Blogs

Book Recommendations