Pourquoi Go cache-t-il les résultats des tests ? (Et comment ça gâche la vie)
\n\nImaginez : vous codez en Go, vous lancez go test, vous voyez un coche vert... mais quelque chose cloche. Vous avez corrigé un bug, vous relancez les tests — et à nouveau le feu vert. Pourtant, le bug est toujours là ! Ça vous dit quelque chose ? Bienvenue dans le monde de la mise en cache des tests Go.
Go est un langage qui aime la vitesse. Pour ne pas relancer les mêmes tests dix fois, le compilateur met en cache les résultats. Ça semble pratique, jusqu'à ce que vous soyez confronté à une situation où le cache des tests Go commence à jouer contre vous. Cela frappe particulièrement les développeurs qui travaillent avec des tests d'intégration, le système de fichiers ou des API externes.
\n\nDans cet article, nous allons décortiquer deux approches pour résoudre le problème : le force retesting (redémarrage forcé) et la désactivation complète du cache des tests. Vous apprendrez quand utiliser quoi, et vous obtiendrez des exemples de code fonctionnels.
\n\nComment fonctionne la mise en cache des tests en Go
\n\nAvant de casser, comprenons comment ça marche. Go met en cache les résultats des tests sur la base d'un hachage de :
\n- \n
- Le code source (fichiers
.go) \n - Les fichiers de test \n
- Les variables d'environnement \n
- Les flags de compilation \n
Si rien n'a changé — Go affiche simplement le résultat mis en cache. Rapide ? Oui. Dangereux ? Et comment ! Imaginez que votre test dépende de l'heure, de nombres aléatoires ou d'un service externe. Le cache dira : « Tout va bien ! », alors qu'en réalité le test aurait échoué depuis longtemps.
\n\n// Exemple de test qui sera faussement vert à cause du cache\nfunc TestCurrentTime(t *testing.T) {\n now := time.Now()\n if now.Year() != 2024 {\n t.Errorf("L'année devrait être 2024, obtenu %d", now.Year())\n }\n}\n\nLancez ce test une fois — il passera. Vous corrigez l'année en 2025 dans le code ? Le cache affichera quand même l'ancien résultat. Et vous vous demanderez pourquoi la CI échoue, alors qu'en local tout « marche ».
\n\nApproche 1 : Force retesting (redémarrage forcé)
\n\nLa méthode la plus populaire pour lutter contre le cache est le flag -count=1. C'est le force retesting dans sa forme la plus pure. Il dit à Go : « Ne fais pas confiance au cache, relance le test à nouveau ».
// Lancement avec redémarrage forcé\ngo test -count=1 ./...\n\nPourquoi -count=1 et pas -count=0 ? Parce que -count définit le nombre d'exécutions du test. 1 est la valeur minimale qui désactive le cache. 0 ne lancera tout simplement rien.
Quand utiliser le force retesting
\n- \n
- Tests d'intégration qui accèdent à une base de données ou une API \n
- Tests avec données aléatoires (fuzz tests, génération d'UUID) \n
- Tests dépendant du temps (timeouts, dates) \n
- Développement local, lorsque vous modifiez fréquemment le code \n
Exemple : test d'intégration avec force retesting
\n\npackage db_test\n\nimport (\n "testing"\n "time"\n)\n\nfunc TestDatabaseConnection(t *testing.T) {\n // Ce test dépend d'un serveur en direct\n // Sans -count=1, il pourrait afficher un résultat obsolète\n db := connectToDatabase()\n if err := db.Ping(); err != nil {\n t.Fatalf("Impossible de se connecter : %v", err)\n }\n \n // Simulation d'un délai temporel\n time.Sleep(100 * time.Millisecond)\n if err := db.Query("SELECT 1"); err != nil {\n t.Errorf("Requête échouée : %v", err)\n }\n}\n\nOn lance : go test -count=1 -v ./db/. Maintenant, chaque exécution est honnête. Mais il y a un bémol : le force retesting ne résout pas le problème globalement. Si vous oubliez le flag, le cache reviendra.
Approche 2 : Désactivation complète du cache des tests
\n\nLa deuxième option est radicale. Vous dites simplement à Go : « Ne mets rien en cache ». Cela se fait via la variable d'environnement GOCACHE=off ou le flag -count=1