Couverture de code par les tests en Go : de la « coche verte » à la qualité réelle
\n\nDans le monde du développement Go, la phrase « j’ai 95 % de couverture » sonne fièrement. Mais souvent, ce chiffre cache un vide : les tests ne vérifient que le chemin heureux, tandis que les cas limites et les erreurs restent à la traîne. Dans cet article, nous allons voir comment mesurer réellement la couverture de code par les tests en Go, quelles métriques sont vraiment importantes, et quels outils peuvent transformer les tests d’une formalité en un puissant outil de contrôle qualité.
\n\nNous ne nous contenterons pas de paraphraser la documentation. À la place, nous proposons des exemples concrets, des pièges et des conseils pratiques pour ceux qui codent en Go et veulent dormir sur leurs deux oreilles.
\n\nPourquoi simplement 80 % est mauvais ?
\n\nSupposons que vous ayez une fonction :
\n\nfunc ProcessOrder(amount float64, discount bool) (float64, error) {\n if amount <= 0 {\n return 0, errors.New("amount must be positive")\n }\n if discount {\n amount *= 0.9\n }\n return amount, nil\n}\n\nVous avez écrit un seul test : ProcessOrder(100, true) → 90, nil. La couverture ? 100 % des lignes. Mais vous n’avez pas vérifié le cas avec amount <= 0 ni le cas sans réduction. Formellement, la couverture est excellente. En réalité, les bugs sont garantis. Voilà pourquoi les métriques de couverture de code par les tests en Go doivent être considérées en conjonction avec d’autres indicateurs.
Outils de couverture : du simple au complexe
\n\n1. Le go test -cover intégré
\n\nLe moyen le plus simple de connaître la couverture de code par les tests en Go est le flag -cover :
go test -cover ./...\n\nSortie :
\nok myproject/orders 0.234s coverage: 72.3% of statements\n\nMais ce n’est qu’un chiffre global. Pour voir quelles lignes ne sont pas couvertes, utilisez -coverprofile :
go test -coverprofile=coverage.out ./...\ngo tool cover -html=coverage.out\n\nUn navigateur s’ouvrira avec un surlignage : vert pour couvert, rouge pour non couvert. C’est un premier pas vers la compréhension des métriques de couverture Go.
\n\n2. go tool cover : modes et nuances
\n\ngo tool cover prend en charge trois modes :
- \n
- set — la ligne a-t-elle été exécutée au moins une fois (par défaut) \n
- count — combien de fois chaque ligne a été exécutée \n
- atomic — count, mais avec des compteurs atomiques pour les tests parallèles \n
Pour l’analyse de la couverture par les tests Golang dans du code multithreadé, utilisez atomic, sinon vous risquez d’obtenir des compteurs incorrects à cause de race conditions.
\n\ngo test -covermode=atomic -coverprofile=coverage.out ./...\n\n3. Race detector — couverture cachée
\n\nLes courses de données sont l’un des principaux problèmes du code Go. Même si la couverture des lignes est de 100 %, le race detector peut trouver des erreurs que les tests n’ont pas remarquées. Lancez les tests avec le flag -race :
go test -race -cover ./...\n\nImportant : le race detector ralentit les tests de 2 à 20 fois, mais pour les modules critiques, c’est une pratique obligatoire. Incluez-le dans votre CI pour les paquets clés.
\n\nMétriques qui comptent vraiment
\n\nLe pourcentage de couverture des lignes n’est que la partie émergée de l’iceberg. Voici ce qu’il faut suivre :
\n\n1. Couverture des branches (branch coverage)
\n\nLe go test -cover standard compte les lignes, pas les branches. Pour la couverture de code par les tests Go au niveau des branches, utilisez gocov ou go-test-coverage. Exemple :
go get github.com/axw/gocov/gocov\ngocov test ./... | gocov report\n\nVous verrez non seulement les lignes, mais aussi le nombre de conditions non couvertes. Par exemple, pour une fonction avec deux if — 4 branches, dont 2 couvertes.
\n\n2. Tests de mutation (mutation testing)
\n\nLa façon la plus honnête d’évaluer la qualité des tests est