Tests en Go : unitaires, d'intégration, e2e au niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : Pourquoi les tests avancés sont un must have en Go



Go (Golang) est réputé pour sa simplicité et ses outils de test intégrés. Cependant, lorsqu'un projet dépasse le cadre du "Hello, World", le standard go test ne suffit plus. Au niveau avancé, les développeurs sont confrontés à des questions : comment isoler correctement les tests, comment tester le travail avec une base de données, comment simuler des services externes et comment organiser une vérification de bout en bout de l'ensemble de l'application.



Dans cet article, nous aborderons trois niveaux de test — Unitaires, d'Intégration et E2E — avec des exemples issus de la pratique réelle. Vous apprendrez à utiliser les mocks, les conteneurs pour les tests d'intégration et à construire un pipeline fiable pour le CI/CD. Ce contenu est destiné aux développeurs qui connaissent déjà les bases de Go et souhaitent élever la qualité de leur code à un nouveau niveau.



1. Tests unitaires : isolation, mocks et le pattern Table-Driven Tests



Les tests unitaires vérifient le fonctionnement d'un seul module (fonction, méthode) en totale isolation des dépendances externes. En Go, on utilise souvent des interfaces et des bibliothèques de mocking, comme testify/mock ou gomock.



1.1. Les interfaces comme base des tests



Pour remplacer un service réel par un mock, le code doit dépendre d'une interface, et non d'une implémentation concrète. Prenons l'exemple d'un service d'envoi de notifications.



// notifier.gotype Notifier interface {    Send(to string, message string) error}

type UserService struct { Notifier Notifier}

func (s *UserService) NotifyUser(userID string) error { // logique pour obtenir l'email de l'utilisateur email := userID + "@example.com" return s.Notifier.Send(email, "Welcome!")}


1.2. Création d'un mock avec testify/mock



Installons la bibliothèque : go get github.com/stretchr/testify.



// notifier_mock.go (dans le package user_test)type NotifierMock struct {    mock.Mock}

func (m *NotifierMock) Send(to string, message string) error { args := m.Called(to, message) return args.Error(0)}


1.3. Table-Driven Tests



C'est un pattern standard en Go pour tester de nombreux cas. Il améliore la lisibilité et simplifie l'ajout de nouveaux tests.



// user_service_test.gofunc TestNotifyUser(t *testing.T) {    tests := []struct {        name      string        userID    string        mockError error        expectErr bool    }{        {"success", "user1", nil, false},        {"fail_send", "user2", errors.New("send error"), true},    }

for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockNotifier := new(NotifierMock) service := &UserService{Notifier: mockNotifier}

mockNotifier.On("Send", tt.userID+"@example.com", "Welcome!").Return(tt.mockError)

err := service.NotifyUser(tt.userID) if tt.expectErr { assert.Error(t, err) } else { assert.NoError(t, err) } mockNotifier.AssertExpectations(t) }) }}


Bonne pratique : Utilisez t.Run pour les sous-tests — cela permet d'exécuter chaque cas individuellement et de voir lequel a échoué.



2. Tests d'intégration : travail avec la base de données et les services externes



Les tests d'intégration vérifient l'interaction de plusieurs composants : le code Go avec une base de données, un serveur API avec un cache, etc. Le principal défi est de gérer l'état de l'environnement. C'est là que les Testcontainers viennent à la rescousse.



2.1. Testcontainers pour Go



Testcontainers permet de lancer des conteneurs Docker directement depuis les tests. Cela offre un environnement propre et isolé pour chaque exécution.



Installation : go get github.com/testcontainers/testcontainers-go



2.2. Exemple : test

Blogs

Book Recommendations