Ce tutoriel fait partie du parcours « Go de zéro ». Pour la vue d’ensemble, lisez d’abord le guide principal.
Tester, compiler et déployer un binaire Go
GareBook fonctionne sur votre machine. Mais « ça marche chez moi » n’est pas un objectif : l’objectif, c’est que ça marche sur le serveur, de façon fiable, et que ça continue de marcher quand vous modifierez le code. Deux outils de Go répondent à ça, et tous deux sont intégrés, sans rien à installer : le framework de test (go test) et le compilateur (go build), capable de produire un binaire pour un autre système que le vôtre.
Ce dernier tutoriel du parcours boucle la boucle. Vous allez écrire des tests automatisés pour la logique de GareBook, compiler le binaire de production, le générer pour un serveur Linux depuis votre PC, et le mettre en ligne. À la fin, vous saurez livrer du Go pour de vrai.
🎯 Ce que vous allez apprendre
- Écrire des tests automatisés avec le package
testinget le motif « table-driven » ; - Tester une route HTTP sans démarrer de vrai serveur, avec
net/http/httptest; - Produire un binaire de production optimisé avec
go build; - Compiler depuis Windows un binaire destiné à Linux (compilation croisée) et le déployer.
🛠️ Ce que vous allez construire
Une suite de tests qui valide le calcul de prix et la route de consultation de GareBook, puis le binaire Linux prêt à déposer sur un VPS, et enfin la procédure pour le faire tourner en continu derrière un service système. Vous passerez du code testé au service en ligne.
Prérequis
- Avoir suivi le tutoriel sur l’API REST : un projet GareBook avec ses fonctions et ses routes ;
- Un accès SSH à un serveur Linux (un VPS d’entrée de gamme suffit) pour la partie déploiement ;
- Niveau : débutant à l’aise. Test express : si vous savez lancer
go run .sur votre API, vous êtes prêt. - ⏱️ Temps estimé : ~45 minutes.
Étape 1 — Votre premier test
En Go, les tests vivent dans des fichiers nommés quelquechose_test.go, à côté du code qu’ils vérifient. Une fonction de test commence par Test, prend un paramètre *testing.T, et signale un échec avec t.Errorf. Aucune bibliothèque externe : tout est dans la bibliothèque standard. Testons la fonction prixBillet écrite plus tôt. Créez prix_test.go :
package main
import "testing"
func TestPrixBillet(t *testing.T) {
got := prixBillet(264, 13.5)
want := 3600
if got != want {
t.Errorf("prixBillet(264, 13.5) = %d ; attendu %d", got, want)
}
}
Lancez la suite avec go test ./.... Si tout passe, Go affiche ok et le temps écoulé. Provoquez volontairement un échec en changeant want à 9999 : Go affiche le message d’erreur exact avec la valeur obtenue et la valeur attendue. C’est tout l’intérêt d’un test — il dit précisément ce qui cloche, sans que vous ayez à déboguer à l’aveugle.
✅ Point d’étape —
go test ./...afficheokpour votre package. Vous avez un filet de sécurité : si une modification future casseprixBillet, le test vous le dira immédiatement.
Étape 2 — Les tests « en table »
Tester un seul cas ne suffit pas. La façon idiomatique en Go est le test « table-driven » : on liste les cas (entrée + résultat attendu) dans une table, et on boucle dessus. C’est compact, lisible, et facile à étendre — ajouter un cas, c’est ajouter une ligne. Réécrivons le test ainsi :
func TestPrixBilletTable(t *testing.T) {
cas := []struct {
nom string
distance int
prixKm float64
attendu int
}{
{"trajet court", 70, 13.5, 1000},
{"trajet moyen", 264, 13.5, 3600},
{"trajet long", 500, 13.5, 6800},
}
for _, c := range cas {
t.Run(c.nom, func(t *testing.T) {
got := prixBillet(c.distance, c.prixKm)
if got != c.attendu {
t.Errorf("%s : prixBillet(%d, %.1f) = %d ; attendu %d",
c.nom, c.distance, c.prixKm, got, c.attendu)
}
})
}
}
Chaque cas devient un sous-test grâce à t.Run(c.nom, ...), avec son propre nom. Si un seul cas échoue, Go vous dit lequel par son nom, les autres continuant d’être évalués. Lancez go test -v ./... : l’option -v (verbeux) affiche chaque sous-test individuellement. Adaptez les valeurs attendues à votre formule réelle d’arrondi — l’essentiel est le motif, que vous réutiliserez pour toute fonction de calcul.
Étape 3 — Tester une route HTTP sans serveur
Comment tester la route GET /trajets/{id} sans lancer un vrai serveur et faire des appels réseau ? Le package net/http/httptest simule une requête et capture la réponse en mémoire. On fabrique une fausse requête, un « enregistreur » de réponse, on appelle directement la fonction de traitement, et on inspecte le résultat. Créez api_test.go :
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestVoirTrajet(t *testing.T) {
// Fausse requête vers /trajets/1
req := httptest.NewRequest("GET", "/trajets/1", nil)
req.SetPathValue("id", "1") // simule le paramètre d'URL
rec := httptest.NewRecorder()
voirTrajet(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("statut = %d ; attendu %d", rec.Code, http.StatusOK)
}
if ct := rec.Header().Get("Content-Type"); ct != "application/json" {
t.Errorf("Content-Type = %q ; attendu application/json", ct)
}
}
httptest.NewRequest crée une requête de test, httptest.NewRecorder capture ce que le handler écrit, et SetPathValue injecte le paramètre d’URL qu’aurait normalement extrait le routeur. On vérifie ensuite le code de statut et l’en-tête. Ce test tourne en quelques millisecondes, sans réseau, sans port — parfait pour une suite de tests rapide qu’on lance à chaque modification. Mesurez au passage la couverture de vos tests avec go test -cover ./....
Au fil du temps, votre suite de tests grandit, et relancer tout devient long. Deux options aident. D’abord, le filtrage : go test -run TestVoirTrajet ./... n’exécute que les tests dont le nom correspond au motif donné — pratique quand on travaille sur une seule fonction. Ensuite, au-delà de la justesse, Go sait mesurer la performance : une fonction nommée BenchmarkX(b *testing.B) est un banc d’essai que go test -bench=. exécute en boucle pour chronométrer votre code. On ne s’en sert pas tous les jours, mais savoir que c’est intégré, sans aucun outil tiers, fait partie de ce qui rend l’écosystème Go si cohérent : tester, mesurer la couverture et chronométrer se font avec une seule et même commande.
✅ Point d’étape —
go test ./...exécute vos tests de calcul et de route HTTP, tout en vert. Vous testez la logique métier et le comportement de l’API sans rien lancer manuellement.
Étape 4 — Compiler le binaire de production
Les tests passent : il est temps de produire le binaire à déployer. Un go build simple suffit, mais on peut l’optimiser pour la production. L’option -ldflags="-s -w" retire les informations de débogage et allège le binaire, et nommer la sortie clarifie le livrable :
# Binaire pour votre système actuel, allégé
go build -ldflags="-s -w" -o garebook
Vous obtenez un fichier garebook de quelques mégaoctets, autonome. Mais il y a un détail : ce binaire est compilé pour votre système. Si vous développez sous Windows et déployez sur un serveur Linux, il ne tournera pas tel quel. C’est là qu’intervient la fonctionnalité la plus appréciée de Go : la compilation croisée. Deux variables d’environnement, GOOS (système) et GOARCH (architecture), suffisent à produire un binaire pour une autre plateforme :
# Depuis Windows (PowerShell), compiler pour un serveur Linux 64 bits
$env:GOOS = "linux"
$env:GOARCH = "amd64"
$env:CGO_ENABLED = "0"
go build -ldflags="-s -w" -o garebook-linux
# Depuis macOS / Linux (bash), même cible
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o garebook-linux
CGO_ENABLED=0 produit un binaire entièrement statique, sans dépendance à des bibliothèques C du système — il tournera sur quasiment n’importe quel Linux, y compris une image minimale. Vous venez, depuis votre PC, de fabriquer l’exécutable exact qui tournera sur le serveur. Aucun runtime à installer là-bas, aucune dépendance à résoudre. C’est ce qui rend le déploiement de Go si reposant.
Étape 5 — Déployer et faire tourner en continu
Reste à mettre garebook-linux en ligne. On le transfère par SSH, on le rend exécutable, et on le confie à systemd pour qu’il redémarre tout seul après un reboot ou une coupure. D’abord le transfert :
# Copier le binaire sur le serveur
scp garebook-linux utilisateur@mon-serveur:/home/utilisateur/garebook
# Se connecter et le rendre exécutable
ssh utilisateur@mon-serveur
chmod +x /home/utilisateur/garebook
Lancer le binaire à la main fonctionne, mais il s’arrêterait dès la fermeture de la session SSH. Pour un service durable, on crée une unité systemd. Créez le fichier /etc/systemd/system/garebook.service :
[Unit]
Description=API GareBook
After=network.target
[Service]
ExecStart=/home/utilisateur/garebook
Restart=always
User=utilisateur
[Install]
WantedBy=multi-user.target
Puis activez-le. Restart=always est la ligne clé : si le programme s’arrête ou si le serveur redémarre après une coupure de courant, systemd le relance automatiquement.
sudo systemctl daemon-reload
sudo systemctl enable --now garebook
sudo systemctl status garebook # vérifier qu'il tourne
Votre API GareBook tourne maintenant en continu sur le serveur, sur le port 8080. En production, on la place derrière un reverse proxy comme Nginx qui gère le HTTPS et expose le service sur le port 443 — c’est l’objet d’un autre guide. Mais le cœur du travail est fait : du code testé, compilé, déployé, et résilient aux redémarrages.
🐞 Pièges fréquents
| Symptôme / erreur | Cause probable | Correctif |
|---|---|---|
no test files |
Le fichier de test n’est pas nommé *_test.go |
Renommez-le, par exemple prix_test.go |
| Le test ne s’exécute pas | La fonction ne commence pas par Test ou n’a pas *testing.T |
Signature exacte : func TestX(t *testing.T) |
| Le binaire Linux ne se lance pas sur le serveur | Compilé pour la mauvaise plateforme | Recompilez avec GOOS=linux GOARCH=amd64 |
exec format error à l’exécution |
Mauvaise architecture (ARM vs amd64) | Vérifiez l’architecture du serveur avec uname -m et ajustez GOARCH |
Le service systemd ne démarre pas |
Chemin ExecStart erroné ou binaire non exécutable |
chmod +x le binaire et vérifiez le chemin absolu ; lisez journalctl -u garebook |
🌍 Adaptation au contexte ouest-africain
La compilation croisée est un atout majeur ici. Vous développez sur le matériel que vous avez — souvent un PC Windows — et vous produisez en une commande le binaire Linux pour un VPS hébergé n’importe où. Pas besoin d’une machine Linux dédiée, pas de double environnement à maintenir. Et comme le binaire est statique et léger, le transfert par scp est rapide même sur une connexion modeste : quelques mégaoctets contre les centaines de mégaoctets de dépendances d’autres écosystèmes.
Le Restart=always de systemd mérite une mention spéciale dans un contexte de coupures électriques fréquentes : votre service revient tout seul après chaque redémarrage du serveur, sans intervention. Pour empaqueter le binaire de façon encore plus reproductible, le conteneur Docker est une suite naturelle — un binaire Go statique tient dans une image minuscule.
✅ Récapitulatif
Vous savez maintenant livrer du Go de bout en bout. Vous écrivez des tests automatisés avec le package testing, vous structurez vos cas en table avec t.Run, et vous testez une route HTTP en mémoire grâce à httptest. Vous compilez un binaire de production optimisé, vous le générez pour Linux depuis votre machine par compilation croisée, et vous le déployez en service durable avec systemd. GareBook est en ligne, testé et résilient — vous avez parcouru tout le chemin, de l’installation de Go au service en production. Félicitations : vous tenez les fondamentaux d’un développeur Go.
🧾 Aide-mémoire
| Commande | Rôle |
|---|---|
go test ./... |
Lance tous les tests du projet |
go test -v ./... |
Tests en mode verbeux (chaque sous-test) |
go test -cover ./... |
Affiche la couverture de test |
t.Run(nom, func) |
Définit un sous-test nommé |
httptest.NewRecorder() |
Capture la réponse d’un handler |
go build -ldflags="-s -w" -o nom |
Binaire de production allégé |
GOOS=linux GOARCH=amd64 go build |
Compilation croisée vers Linux |
systemctl enable --now garebook |
Active et démarre le service |
💪 À vous de jouer
Ajoutez un test table-driven pour la fonction categorie(dureeHeures float64) du tutoriel sur la syntaxe, couvrant un trajet court, moyen et long. Puis générez un binaire pour un serveur ARM 64 bits (un mini-PC ou certains VPS) et identifiez la valeur de GOARCH à utiliser.
Voir une solution
func TestCategorie(t *testing.T) {
cas := []struct {
duree float64
attendu string
}{
{1.5, "court"},
{3, "moyen"},
{8, "long"},
}
for _, c := range cas {
if got := categorie(c.duree); got != c.attendu {
t.Errorf("categorie(%.1f) = %q ; attendu %q", c.duree, got, c.attendu)
}
}
}
Pour un serveur ARM 64 bits, on utilise GOARCH=arm64 : GOOS=linux GOARCH=arm64 go build -o garebook-arm64. Go connaît un large éventail de couples GOOS/GOARCH, listés par go tool dist list.
Tutoriels frères
- Une première API REST avec net/http — le tutoriel précédent.
- Installer Go et lancer son premier programme — pour reprendre le parcours depuis le début.
Pour aller plus loin
- 🔝 Retour au guide principal : Go (Golang) : le guide complet pour débuter
- Empaqueter votre binaire dans une image légère : Docker pour débuter
- Documentation officielle des tests : pkg.go.dev/testing
FAQ
Faut-il une bibliothèque comme testify pour tester ?
Non. Le package testing de la bibliothèque standard suffit pour l’immense majorité des besoins. Des bibliothèques comme testify ajoutent des assertions plus concises, mais commencez sans : vous comprendrez mieux ce qui se passe.
Comment connaître l’architecture de mon serveur ?
Connectez-vous en SSH et lancez uname -m : x86_64 signifie GOARCH=amd64, aarch64 signifie GOARCH=arm64. Compilez en conséquence.
Pourquoi CGO_ENABLED=0 ?
Cela force un binaire 100 % Go, sans liaison à des bibliothèques C du système. Le résultat est entièrement statique et portable : il tourne sur n’importe quelle distribution Linux, y compris une image conteneur minimale. Sans ça, le binaire pourrait réclamer des bibliothèques absentes du serveur.
Dois-je déployer le binaire ou le code source ?
Le binaire. C’est tout l’intérêt de Go : on livre un seul fichier exécutable autonome. Le serveur n’a pas besoin d’avoir Go installé, ni le code source, ni les dépendances. Vous copiez le binaire, vous le lancez.
Mots-clés : go test, tests Go, table-driven, httptest, go build, compilation croisée, GOOS GOARCH, déploiement Go, systemd, débuter Golang.