Pourquoi les tests en Go ne sont pas effrayants, mais nécessaires
\n\nLorsque vous écrivez pour la première fois en Go, il semble que le compilateur attrape presque tout : les types sont stricts, les erreurs sont explicites, nil est sous contrôle. Mais dès que votre projet atteint 500+ lignes, vous comprenez : on ne peut pas vivre sans tests. Une modification à un endroit en casse un autre, et vous ne l'apprenez qu'en production.
Dans cet article, je vais vous montrer par où commencer les tests en Go pour un développeur débutant. Nous aborderons les tests unitaires, les tests tabulaires, les mocks et la couverture de code. Pas de blabla — uniquement des exemples concrets et des conseils pratiques.
\n\nSi vous écrivez en Go depuis au moins quelques mois, ce contenu vous fera gagner des heures de débogage.
\n\nCe qu'il faut savoir avant de commencer
\n\nGo fournit le package intégré testing — rien à installer en plus. Les tests sont écrits dans des fichiers avec le suffixe _test.go et sont lancés avec la commande :
go test ./...\n\nRègles de base :
\n- \n
- La fonction de test doit s'appeler
TestXxx(t *testing.T), où Xxx est le nom de la fonction testée avec une majuscule. \n - Les fichiers de test se trouvent à côté du code testé. \n
- Les erreurs sont signalées via
t.Error()out.Fatal(). \n
Passons directement à la pratique.
\n\nÉcrire notre premier test unitaire en Go
\n\nSupposons que nous ayons une fonction simple qui additionne deux nombres :
\n\n// calc.go\npackage calc\n\nfunc Sum(a, b int) int {\n return a + b\n}\n\nCréons le fichier calc_test.go dans le même dossier :
// calc_test.go\npackage calc\n\nimport "testing"\n\nfunc TestSum(t *testing.T) {\n result := Sum(2, 3)\n expected := 5\n\n if result != expected {\n t.Errorf("Sum(2,3) = %d; want %d", result, expected)\n }\n}\n\nLançons le test :
\n\ngo test -v\n\nVous verrez un PASS vert — votre première victoire en test. Notez : nous utilisons t.Errorf (non fatal) — le test continue même si un cas échoue.
Tests tabulaires : quand un seul test n'est pas pratique
\n\nImaginez devoir tester une fonction avec une dizaine de données d'entrée différentes. Écrire 10 tests séparés ? Non, en Go, on utilise les tests tabulaires (table-driven tests). C'est un standard dans la communauté Go.
\n\nAjoutons une fonction de division à notre calc.go :
func Divide(a, b int) (int, error) {\n if b == 0 {\n return 0, errors.New("division by zero")\n }\n return a / b, nil\n}\n\nÉcrivons maintenant un test tabulaire :
\n\nfunc TestDivide(t *testing.T) {\n tests := []struct {\n name string\n a, b int\n expected int\n wantErr bool\n }{\n {"positive", 10, 2, 5, false},\n {"negative", -6, 3, -2, false},\n {"zero division", 5, 0, 0, true},\n {"same numbers", 7, 7, 1, false},\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n got, err := Divide(tt.a, tt.b)\n if tt.wantErr {\n if err == nil {\n t.Error("expected error, got nil")\n }\n return\n }\n if err != nil {\n t.Errorf("unexpected error: %v", err)\n }\n if got != tt.expected {\n t.Errorf("Divide(%d,%d) = %d; want %d", tt.a, tt.b, got, tt.expected)\n }\n })\n }\n}\n\nCe qui est génial ici :
\n- \n
- Chaque cas est un sous-test nommé. Si l'un échoue, les autres s'exécutent. \n
- Facile d'ajouter de nouveaux cas — il suffit d'ajouter une ligne dans la structure. \n
- Le code se lit comme une spécification. \n
Lancez avec le drapeau -v — vous verrez les noms de tous les sous-tests. C'est très pratique pour le débogage.