Tests de mutation en Go : comment attraper ce que les tests unitaires laissent passer

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 : les tests passent, mais les bugs persistent ?

\n\n

Imaginez la situation : vous avez écrit un module en Go, couvert par des tests unitaires à 95% selon go test -cover, tous les tests sont verts. Vous êtes convaincu que le code fonctionne parfaitement. Mais en production, un bug apparaît. Cela vous dit quelque chose ?

\n\n

Le problème est que la métrique de couverture de code (code coverage) n'est qu'un nombre de lignes qui ont été exécutées. Elle ne dit pas ce que les tests vérifient réellement. On peut avoir 100% de couverture sans jamais vérifier qu'une fonction retourne la bonne valeur, et non pas simplement qu'elle ne plante pas avec une panique.

\n\n

C'est là qu'intervient le test de mutation (mutation testing) en Go — une méthode qui introduit artificiellement des erreurs dans votre code et vérifie si les tests peuvent les détecter. Si les tests ne tombent pas sur le code muté, cela signifie que vos tests sont inutiles.

\n\n

Dans cet article, nous allons voir ce qu'est le test de mutation en Go, comment le configurer, et pourquoi c'est un must-have pour les projets où la fiabilité est critique. C'est parti !

\n\n

Qu'est-ce que le test de mutation ?

\n\n

Le test de mutation est une méthode d'évaluation de la qualité des tests qui consiste à introduire de petites modifications (mutations) dans le programme, simulant des erreurs typiques de développeur. Ensuite, les tests sont exécutés. Si au moins un test échoue, la mutation est "tuée", le test fonctionne. Si tous les tests réussissent, la mutation a "survécu", et c'est un signal d'alarme : vous avez une faille dans vos tests.

\n\n

En Go, le test de mutation est souvent appelé mutation testing golang, et il est particulièrement utile pour vérifier la logique métier, les validateurs, les analyseurs et autres composants critiques.

\n\n

Exemple de mutation

\n\n

Supposons que vous ayez une fonction simple :

\n\n
func IsEven(n int) bool {\n    return n%2 == 0\n}
\n\n

Une mutation typique consiste à remplacer == par != :

\n\n
func IsEven(n int) bool {\n    return n%2 != 0\n}
\n\n

Si votre test vérifie seulement que IsEven(2) ne plante pas, mais ne vérifie pas que le résultat est true, alors la mutation survivra. Le test passera, même si la fonction fonctionne désormais à l'envers.

\n\n

Pourquoi la simple couverture de code ne suffit-elle pas ?

\n\n

De nombreux développeurs Go ont l'habitude de se fier à go test -cover. C'est une métrique utile, mais elle est trompeuse. Prenons un exemple :

\n\n
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

Test :

\n\n
func TestDivide(t *testing.T) {\n    result, err := Divide(10, 2)\n    if err != nil {\n        t.Fatal(err)\n    }\n    if result != 5 {\n        t.Errorf("expected 5, got %d", result)\n    }\n}
\n\n

Couverture ? 100% — toutes les lignes ont été exécutées. Mais que se passe-t-il si quelqu'un remplace accidentellement a / b par a * b ? Le test ne le remarquera pas, car 10 * 2 = 20, alors que nous attendions 5. Le test échouera-t-il ? Non, si nous ne vérifions pas la valeur exacte.

\n\n

Le test de mutation en Go identifiera immédiatement ce problème en créant un mutant avec la multiplication et en vérifiant si le test échoue.

\n\n

Outils pour le test de mutation en Go

\n\n

L'outil principal est go-mutesting. C'est une bibliothèque populaire qui crée automatiquement des mutations et exécute les tests. Installation :

\n\n
go get github.com/zimmski/go-mutesting/cmd/go-mutesting
\n\n

Il existe aussi des alternatives, comme mutesting de la société "Go Test It", mais go-mutesting est la référence de facto.

\n\n

Comment l'exécuter

\n\n

Exécution de base :

\n\n
go-mutesting ./...
\n\n

Cette commande trouvera tous les fichiers _test.go dans le projet et vérifiera quelles mutations survivent. Le résultat s'affiche dans la console avec un rapport détaillé.

\n\n

Exemple pratique : test de mutation en Go

\n\n

Créons un package simple calculator avec des fonctions d'addition et

Blogs

Book Recommendations