Tests Go en 2026 : Tests Unitaires, Mocks et Questions d'Entretien Technique
Guide complet sur les tests en Go : écriture de tests unitaires avec le package testing, création de mocks avec gomock, tests orientés tableaux et préparation aux entretiens techniques.

Le framework de test de Go repose sur le package standard testing, inclus dans chaque installation de Go sans dépendance externe. Contrairement aux frameworks d'autres langages, l'approche de Go privilégie la simplicité : les fichiers de test cohabitent avec le code de production, les fonctions de test suivent une convention de nommage, et la commande go test gère la découverte et l'exécution.
Les candidats qui écrivent des tests orientés tableaux, utilisent les interfaces pour l'injection de dépendances et comprennent quand le mocking apporte de la valeur plutôt que du bruit.
Écrire des Tests Unitaires avec le Package testing
Chaque fichier de test se termine par _test.go et appartient au même package que le code testé. Les fonctions de test commencent par Test suivi d'un nom en majuscule. Le paramètre *testing.T fournit des méthodes pour signaler les échecs.
package calculator
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2, 3) = %d; want 5", result)
}
}L'exécution de go test ./... lance tous les tests du module courant. Le flag -v affiche les noms des tests individuels et leur statut.
Tests Orientés Tableaux : Le Standard Go
Les tests orientés tableaux réduisent la duplication et rendent l'ajout de nouveaux cas trivial. Chaque ligne du tableau représente un scénario avec ses entrées et sorties attendues. Ce pattern apparaît dans la bibliothèque standard Go et dans les bases de code en production.
package validator
import "testing"
func TestValidateEmail(t *testing.T) {
tests := []struct {
name string
email string
wantErr bool
}{
{"valid email", "user@example.com", false},
{"missing at sign", "userexample.com", true},
{"empty string", "", true},
{"unicode local part", "user@例え.jp", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateEmail(tt.email)
if (err != nil) != tt.wantErr {
t.Errorf("ValidateEmail(%q) error = %v, wantErr %v",
tt.email, err, tt.wantErr)
}
})
}
}La méthode t.Run crée des sous-tests qui s'exécutent indépendamment. Les sous-tests en échec indiquent quel cas spécifique a échoué sans arrêter les autres cas.
Injection de Dépendances par les Interfaces
Les interfaces Go permettent de tester du code qui dépend de systèmes externes : bases de données, clients HTTP, systèmes de fichiers. Définir une interface minimale au point d'utilisation permet de remplacer les implémentations réelles par des doubles de test.
package order
// Repository defines the data access methods this service needs
type Repository interface {
FindByID(id string) (*Order, error)
Save(order *Order) error
}
// Service handles order business logic
type Service struct {
repo Repository
}
// NewService creates a service with the given repository
func NewService(repo Repository) *Service {
return &Service{repo: repo}
}
// Process validates and saves an order
func (s *Service) Process(order *Order) error {
if order.Total <= 0 {
return ErrInvalidTotal
}
return s.repo.Save(order)
}Le Service accepte tout type satisfaisant Repository. Le code de production passe une implémentation connectée à la base de données. Les tests passent un mock ou un stub.
Mocking avec gomock et mockgen
Le package gomock génère des implémentations mock à partir de définitions d'interface. La commande mockgen lit les fichiers source et produit des structs mock qui enregistrent les appels et retournent des valeurs configurées.
# Generate mocks for the Repository interface
mockgen -source=service.go -destination=mocks/repository_mock.go -package=mocksUtilisation du mock généré dans les tests :
package order
import (
"testing"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"yourmodule/order/mocks"
)
func TestService_Process_SavesValidOrder(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
order := &Order{ID: "123", Total: 99.99}
// Expect Save to be called once with this order, return nil
mockRepo.EXPECT().
Save(order).
Return(nil).
Times(1)
svc := NewService(mockRepo)
err := svc.Process(order)
assert.NoError(t, err)
}
func TestService_Process_RejectsZeroTotal(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
// No calls expected to repo since validation fails first
svc := NewService(mockRepo)
err := svc.Process(&Order{ID: "456", Total: 0})
assert.ErrorIs(t, err, ErrInvalidTotal)
}Le mock vérifie que Save a été appelé exactement une fois avec l'argument attendu. Si le code testé n'appelle jamais Save, ou l'appelle avec des arguments différents, le test échoue.
Utiliser testify pour les Assertions et les Suites
testify fournit des fonctions d'assertion qui produisent des messages d'échec plus clairs que les vérifications manuelles avec if. Le package assert continue l'exécution après les échecs. Le package require arrête le test immédiatement.
package user
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseUser(t *testing.T) {
input := `{"id": "u1", "name": "Alice"}`
user, err := ParseUser(input)
require.NoError(t, err, "parsing should not fail")
assert.Equal(t, "u1", user.ID)
assert.Equal(t, "Alice", user.Name)
assert.Empty(t, user.Email, "email should default to empty")
}L'appel require.NoError arrête le test si le parsing échoue, évitant les panics de pointeur nil sur les assertions suivantes.
Prêt à réussir tes entretiens Go ?
Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.
Tester les Handlers HTTP avec httptest
Le package net/http/httptest fournit ResponseRecorder pour capturer la sortie des handlers et Server pour exécuter un serveur de test local. La plupart des tests unitaires utilisent ResponseRecorder pour éviter la surcharge réseau.
package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestHealthHandler(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil)
rec := httptest.NewRecorder()
HealthHandler(rec, req)
assert.Equal(t, http.StatusOK, rec.Code)
assert.JSONEq(t, `{"status": "ok"}`, rec.Body.String())
}Pour les handlers qui appellent des services externes, il convient d'injecter un client mock ou d'utiliser httptest.NewServer pour créer un backend fictif.
Questions d'Entretien Courantes sur les Tests Go
Les recruteurs évaluent les connaissances en matière de tests à travers des questions qui révèlent l'expérience avec des bases de code réelles. Voici les patterns qui distinguent les candidats préparés :
« Comment testeriez-vous une fonction qui appelle une API externe ? »
Il faut définir une interface pour le client HTTP, l'injecter dans la fonction ou la struct, et fournir un mock qui retourne des réponses prédéterminées. Cela évite les appels réseau et rend les tests déterministes.
« Quand utiliseriez-vous un stub plutôt qu'un mock ? »
Les stubs retournent des réponses préenregistrées sans vérifier comment ils ont été appelés. Les mocks vérifient que des méthodes spécifiques ont été appelées avec des arguments spécifiques. Les stubs sont préférables quand la valeur de retour importe plus que l'interaction. Les mocks conviennent quand la vérification de l'interaction est l'objectif du test.
« Que sont les tests orientés tableaux et pourquoi Go les privilégie-t-il ? »
Les tests orientés tableaux définissent les cas de test comme des données dans une slice de structs. Ils réduisent le code répétitif, rendent l'ajout de cas trivial et produisent une sortie de test lisible avec t.Run. Ce pattern s'aligne avec la préférence de Go pour un code explicite et répétitif plutôt que des abstractions complexes.
« Comment gérez-vous les fixtures de test ou le setup partagé par plusieurs tests ? »
Il est recommandé d'utiliser TestMain pour le setup et le teardown au niveau du package, et des fonctions helper ou des suites de tests (via testify) pour le setup partagé entre tests liés. L'état global qui crée un couplage entre les tests doit être évité.
Pour préparer un entretien Go, le module de tests Go couvre ces patterns en profondeur avec des questions pratiques.
Exécuter les Tests avec la Couverture et la Détection de Race Conditions
La commande go test accepte des flags qui révèlent les chemins de code non testés et les bugs de concurrence.
# Run tests with coverage report
go test -cover ./...
# Generate HTML coverage visualization
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Detect race conditions (slower, but catches real bugs)
go test -race ./...Le détecteur de race instrumente les accès mémoire et signale les lectures et écritures concurrentes sur la même variable. Exécuter les tests avec -race en CI permet de détecter des bugs qui ne se manifestent que dans certaines conditions de timing.
Organiser les Tests dans les Grandes Bases de Code
À mesure que les projets grandissent, l'organisation des tests affecte la maintenabilité :
- Tests du même package (
package foo) accèdent aux fonctions et champs non exportés. À utiliser pour les tests unitaires qui vérifient le comportement interne. - Tests de package externe (
package foo_test) importent le package comme du code externe. À utiliser pour les tests d'intégration et pour vérifier l'API publique. - Répertoires testdata stockent les fixtures comme les fichiers JSON, les sorties de référence ou les bases de données de seed. Go les ignore lors des builds.
- Build tags séparent les tests unitaires des tests d'intégration qui nécessitent des systèmes externes. Exécuter
go test -tags=integration ./...pour les inclure.
Pour en savoir plus sur les bonnes pratiques Go au-delà des tests, l'article sur les patterns de concurrence couvre les goroutines et les channels.
Points Essentiels à Retenir sur les Tests Go
- Le package
testingest inclus avec Go et ne nécessite aucune dépendance externe - Les tests orientés tableaux réduisent la duplication et constituent le pattern attendu en entretien
- Les interfaces permettent l'injection de dépendances ; elles doivent être définies au point d'utilisation, pas à l'implémentation
gomockgénère des mocks à partir des interfaces ;testifyfournit des assertions plus claireshttptest.ResponseRecordercapture la sortie des handlers sans surcharge réseau- Le flag
-racedétecte les bugs de concurrence que les tests unitaires manquent autrement - Les métriques de couverture guident l'attention mais ne garantissent pas la correction
Passe à la pratique !
Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.
Tu saurais repérer le bug en Go ?
Un vrai bout de code, un bug caché, une tentative par jour. Sans compte pour essayer.

Écrit par
Anthony Fillion-MailletFondateur de SharpSkill
Développeur fullstack depuis plus de 10 ans. Il dirige SharpSkill et répond de tout ce qui y est publié.
Mis à jour le 24 août 2026
Tags
Partager
Articles similaires

Le package context en Go en 2026 : Annulation, Timeouts et Questions d'Entretien
Guide complet sur le package context de Go : gestion de l'annulation, des timeouts et des deadlines. Inclut les questions fréquentes en entretien technique et les bonnes pratiques de production.

Interfaces Go Avancées en 2026 : Composition, Assertions de Type et Questions d'Entretien
Maîtriser la composition d'interfaces Go, les assertions de type et les génériques auto-référentiels de Go 1.26. Exemples pratiques et questions d'entretien technique.

Go SIMD et le Package ArchSIMD en 2026 : Optimisation des Performances et Questions d'Entretien
Découvrez le package simd/archsimd de Go 1.26 : opérations vectorielles natives, optimisation des performances et préparation aux entretiens techniques Go.