Tests d'intégration Go avec Docker : 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

Tests d'intégration Go avec Docker : de la théorie à la pratique avancée

\n\n

Les tests d'intégration sont une étape cruciale dans le développement de microservices en Go. Sans vérifier l'interaction avec les bases de données, les files d'attente de messages et les API externes, vous risquez de vous retrouver avec un "ça marche sur ma machine" dans sa manifestation la plus désagréable. Docker permet de créer des environnements propres et isolés pour chaque test, et les techniques avancées permettent de le faire rapidement, en parallèle et sans douleur. Dans cet article, nous allons décortiquer les approches réelles utilisées par les ingénieurs seniors.

\n\n

1. Pourquoi Docker est le partenaire idéal pour les tests d'intégration en Go

\n\n

Go se compile en un binaire statique, ce qui en fait un candidat idéal pour la conteneurisation. Lors des tests d'intégration, Docker résout trois problèmes clés :

\n
    \n
  • Isolation : chaque test reçoit une base de données ou un Redis frais, sans "déchets" des exécutions précédentes.
  • \n
  • Reproductibilité : les tests fonctionnent de la même manière sur la machine du développeur, dans le CI/CD et en production.
  • \n
  • Vitesse : des conteneurs correctement configurés se lancent en quelques secondes, pas en minutes.
  • \n
\n\n

L'erreur principale des débutants est de lancer un seul conteneur pour tous les tests. Cela entraîne des conditions de concurrence et des bugs "flottants". L'approche avancée : un conteneur par paquet de test, voire par test individuel.

\n\n

2. Testcontainers pour Go : des conteneurs gérés depuis le code

\n\n

La bibliothèque testcontainers-go permet de gérer les conteneurs Docker directement depuis les tests Go. C'est plus élégant que d'écrire des scripts bash ou de dépendre d'un Docker Compose pré-lancé.

\n\n

Installation :

\n
go get github.com/testcontainers/testcontainers-go\ngo get github.com/testcontainers/testcontainers-go/modules/postgres
\n\n

Exemple : test de PostgreSQL avec migrations :

\n
package integration_test\n\nimport (\n    "context"\n    "database/sql"\n    "testing"\n    "time"\n\n    "github.com/testcontainers/testcontainers-go"\n    "github.com/testcontainers/testcontainers-go/modules/postgres"\n    "github.com/testcontainers/testcontainers-go/wait"\n    _ "github.com/lib/pq"\n)\n\nfunc TestUserRepository(t *testing.T) {\n    ctx := context.Background()\n\n    pgContainer, err := postgres.RunContainer(ctx,\n        testcontainers.WithImage("postgres:16-alpine"),\n        postgres.WithDatabase("testdb"),\n        postgres.WithUsername("user"),\n        postgres.WithPassword("password"),\n        testcontainers.WithWaitStrategy(\n            wait.ForLog("database system is ready to accept connections").\n                WithOccurrence(2).\n                WithStartupTimeout(30*time.Second),\n        ),\n    )\n    if err != nil {\n        t.Fatal(err)\n    }\n    defer pgContainer.Terminate(ctx)\n\n    connStr, err := pgContainer.ConnectionString(ctx, "sslmode=disable")\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    db, err := sql.Open("postgres", connStr)\n    if err != nil {\n        t.Fatal(err)\n    }\n    defer db.Close()\n\n    // Ici, exécuter les migrations et les tests\n    _, err = db.Exec(`CREATE TABLE IF NOT EXISTS users (\n        id SERIAL PRIMARY KEY,\n        name TEXT NOT NULL\n    )`)\n    if err != nil {\n        t.Fatal(err)\n    }\n\n    // Tester le repository\n    repo := NewUserRepository(db)\n    user, err := repo.Create(ctx, "Alice")\n    if err != nil {\n        t.Fatal(err)\n    }\n    if user.Name != "Alice" {\n        t.Errorf("expected Alice, got %s", user.Name)\n    }\n}
\n\n

Points clés :

\n
    \n
  • WithWaitStrategy — on attend que PostgreSQL soit réellement prêt, pas seulement que le conteneur soit lancé.
  • \n
  • defer pgContainer.Terminate(ctx) — garantit le nettoyage même en cas de panique.
  • \n
  • Chaque test reçoit sa propre instance de base de données — isolation totale.
  • \n
\n\n

3. Tests parallèles et gestion des ressources

\n\n

Go supporte le parall

Blogs

Book Recommendations