CodeGym /Cours /Go SELF /go tool cover -func/-html — comment interpréter le rappor...

go tool cover -func/-html — comment interpréter le rapport

Go SELF
Niveau 31, Leçon 2
Disponible

1. Pourquoi go tool cover est utile : transformer les pourcentages en carte

Quand vous voyez dans la console quelque chose comme coverage: 42.9% of statements, le cerveau essaie joyeusement d’en tirer une conclusion : « bon, presque la moitié, c’est pas mal ! ». Mais c’est un peu comme évaluer un livre à son poids : il y a un chiffre, mais peu de sens. go tool cover sert à transformer un pourcentage en carte : quelles fonctions n’ont pas été touchées par les tests, quelles branches if sont rouges, où vous avez couvert le « chemin heureux » mais oublié l’erreur. Ce n’est plus une métrique abstraite, c’est de la navigation.

Le profil de couverture (par exemple, coverage.out) — ce sont des données. go tool cover — c’est un « visualiseur » de ces données. Et il a deux « lentilles » principales : -func (tableau par fonction) et -html (surlignage du code source).

Le schéma de fonctionnement est simple :

flowchart LR
    A["go test -coverprofile=coverage.out"] --> B["coverage.out (profil)"]
    B --> C["go tool cover -func=coverage.out"]
    B --> D["go tool cover -html=coverage.out"]
    C --> E["Tableau : fichier/fonction/pourcentage"]
    D --> F["HTML : vert/rouge/gris"]

2. D’où vient coverage.out et à quoi sert-il

Avant d’interpréter le rapport, il faut comprendre l’origine des données. go tool cover ne lance pas vos tests tout seul : il ne sait pas quelles données d’entrée vous avez utilisées, quels tests vous avez exécutés et ce qui s’est passé. Il sait lire un fichier de profil de couverture.

Donc la première étape est toujours la même : générer coverage.out avec la commande go test et l’option -coverprofile. En Go, c’est le chemin standard : -coverprofile active automatiquement la collecte de couverture, donc il n’est pas nécessaire d’ajouter séparément -cover.

Supposons que nous ayons un petit paquet d’étude calc (nous l’utilisons comme bac à sable pour les tests et les exemples) :

package calc

// Abs returns the absolute value of a number.
func Abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

Et un test qui ne couvre que le scénario « positif » :

package calc

import "testing"

func TestAbs_Positive(t *testing.T) {
	if Abs(5) != 5 {
		t.Fatalf("Abs(5) must be 5")
	}
}

Nous générons maintenant le profil de couverture (exemple de commandes à lancer dans le terminal de l’IDE) :

go test -coverprofile=coverage.out

Après cela, vous pouvez voir à la fois le pourcentage global et le succès de l’exécution, et surtout un fichier coverage.out apparaît, que go tool cover sait ensuite lire.

3. go tool cover -func : un rayon X des fonctions

Le mode -func est le moyen le plus rapide de comprendre où regarder en premier. Il affiche la couverture par fonction et le résultat global. On peut le voir comme une « liste de suspects » : où il y a 0%, où il y a 12%, où il y a soudainement 100%.

Il est important de noter que -func est un résumé : il n’explique pas pourquoi une ligne n’est pas couverte et n’indique pas quelle branche if n’a pas été exécutée. En revanche, il fait gagner beaucoup de temps lors du diagnostic initial.

La commande ressemble à ceci :

go tool cover -func=coverage.out

La sortie aura à peu près cette forme (vos chiffres peuvent différer, le format reste le même) :

abs.go:  Abs    50.0%
total:   (statements) 50.0%

Il est important de savoir lire cette ligne comme un contrat :

  • à gauche, on voit généralement le nom du fichier (abs.go) ;
  • ensuite, le nom de la fonction (Abs) ;
  • puis le pourcentage de couverture des instructions (statements) à l’intérieur de cette fonction.

Et la ligne total: (statements) — c’est le total global du paquet/de l’ensemble du profil.

Pourquoi Abs est-il à 50% ? Parce que la fonction comporte deux branches : x < 0 et « sinon ». Votre test n’a couvert que le « sinon ». La branche return -x est restée intacte.

Tableau pour s’orienter rapidement

Ce que vous voyez dans -func Ce que cela signifie en pratique
0.0% pour une fonction Cette fonction n’a pas du tout été exécutée par les tests (ou seulement dans des parties non couvrables, mais cela reste rare au niveau de base).
100.0% pour une fonction Toutes les instructions à l’intérieur de la fonction ont été exécutées au moins une fois (cela ne garantit pas que les tests soient bons).
Un pourcentage « moyen » Souvent, cela signifie des branches if manquées, des return anticipés, des vérifications d’erreurs.
total: (statements) Résumé de tout le profil : pratique comme « avant/après », mais pas comme seul repère.

4. go tool cover -html : surlignage du code source

Quand vous avez déjà trouvé des fonctions suspectes via -func, vous voulez comprendre le détail : quelles lignes n’ont pas été exécutées. Et c’est là que -html génère une page HTML avec le code source coloré : le code couvert est généralement en vert, le code non couvert en rouge, et il existe parfois des zones grises (non instrumentées).

C’est précisément cette méthode qui montre visuellement où il manque des tests : dans quelles branches, quels return, quelles gestions d’erreurs.

Le lancement se fait ainsi :

go tool cover -html=coverage.out

Après le lancement, le navigateur s’ouvre généralement (ou vous ouvrez le fichier manuellement), et vous voyez votre code coloré comme un feu tricolore.

Comment lire le rapport HTML sereinement

Point important : rouge ne veut pas dire « le code est mauvais ». Rouge veut dire « dans l’ensemble actuel de tests, ce code n’a pas été exécuté ». Cela peut être :

  • une branche vraiment oubliée ;
  • une branche impossible à exécuter selon le contrat (et dans ce cas, il faudrait peut-être simplifier le code) ;
  • une branche qui ne s’exécute qu’en cas d’erreur d’entrée/IO (et vous ne l’avez pas testée).

Dans l’exemple avec Abs, le HTML affichera en rouge la ligne return -x, et c’est un signal très concret : « Ajoute un test pour les nombres négatifs ».

5. Comment interpréter la couverture de manière d’ingénieur : réduire les risques

Le piège le plus courant chez les débutants est de commencer à « gonfler les pourcentages » pour les pourcentages. Cela conduit à des tests du type « j’ai appelé la fonction — j’ai vérifié que ça n’a pas planté », et le pourcentage est joli, mais les bugs vivent tranquillement.

La bonne interprétation du rapport de couverture est différente : nous l’utilisons comme indice de nos zones aveugles, surtout dans les branchements et les retours anticipés. La couverture ne prouve pas la justesse, mais elle montre très bien ce que vous n’avez même pas essayé de vérifier.

Il existe plusieurs endroits typiques où le rouge dans le HTML signifie presque toujours une vraie lacune dans les tests.

Branches if/switch et « la seconde moitié de la logique »

Si vous voyez que dans un if une seule branche est verte, c’est une invitation directe : « teste l’alternative ». Parfois l’alternative est un scénario négatif, parfois une valeur limite.

return anticipés et « vérifications d’erreurs »

Très souvent, ce sont les branches de ce type qui apparaissent en rouge :

if err != nil {
	return 0, err
}

Ce n’est pas honteux. C’est normal. Cela signifie simplement que vous n’avez jamais modélisé l’erreur. À notre niveau de cours, nous ne construisons pas encore de mocks complexes, mais même dans des fonctions simples, on peut créer des entrées de test qui mènent à une erreur (par exemple, une mauvaise chaîne pour le parsing).

Code « au cas où »

Parfois, la couverture montre en rouge un morceau de code qui, en réalité, ne devrait jamais s’exécuter (par exemple, un « placeholder » ou un « pas encore supprimé »). Dans ce cas, la couverture ne demande pas « d’écrire un test », elle demande « de prendre une décision » : soit ce code est utile et il faut alors le tester, soit il n’est pas utile et il faut alors le supprimer.

Et oui, supprimer du code est aussi une forme d’optimisation, seulement pour le cerveau.

Fréquence d’exécution et modes de couverture

Parfois, il est utile de comprendre non seulement « exécuté ou non », mais aussi « combien de fois exécuté ». C’est particulièrement visible lorsque vous générez le profil en mode count puis ouvrez le HTML : on obtient presque une « caméra thermique » — ici le code a été exécuté souvent, là peu.

À notre niveau, il faut retenir l’idée suivante : -func fournit un résumé, -html fournit une visualisation, et les modes de couverture influencent les données enregistrées dans le profil.

Mais attention à ne pas confondre la couverture avec le profilage de performances : « exécuté souvent » ne veut pas dire « lent », c’est simplement la fréquence d’exécution des instructions dans le cadre des tests.

6. Exemple : rapport → test → amélioration de la couverture

Faisons un exemple « avant/après » sur notre calc.Abs, pour que le lien « rapport → action » ne soit pas théorique.

Étape 1. Il n’y avait qu’un test positif

Code de la fonction :

package calc

func Abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

Le test était uniquement celui-ci :

package calc

import "testing"

func TestAbs_Positive(t *testing.T) {
	if Abs(5) != 5 {
		t.Fatalf("Abs(5) must be 5")
	}
}

Nous générons le profil et regardons le résumé :

go test -coverprofile=coverage.out
go tool cover -func=coverage.out

Logique attendue du rapport : Abs sera partiellement couverte, car la branche x < 0 n’a pas été exécutée.

Étape 2. Ajout d’un test pour un nombre négatif

Ajoutons un second test :

package calc

import "testing"

func TestAbs_Negative(t *testing.T) {
	if Abs(-7) != 7 {
		t.Fatalf("Abs(-7) must be 7")
	}
}

Maintenant, à nouveau :

go test -coverprofile=coverage.out
go tool cover -func=coverage.out
go tool cover -html=coverage.out

Ce que vous devriez voir à l’œil :

  • dans -func, le pourcentage de Abs passera à 100% (ou tout près, si le fichier contient autre chose) ;
  • dans -html, les deux branches deviendront vertes.

Et cela, c’est le bon rituel : pas une « course au pourcentage », mais « j’ai vu une branche manquante → j’ai ajouté un test qui la parcourt réellement ».

7. Erreurs typiques lors de l’interprétation de go tool cover

Erreur n°1 : ne regarder que le pourcentage global total et ignorer les détails.
Le pourcentage global est pratique pour comparer « avant/après », mais il est presque inutile pour répondre à la question « qu’est-ce que je n’ai pas testé exactement ? ». La bonne habitude : regarder d’abord rapidement -func pour trouver les points faibles, puis ouvrir -html pour voir les lignes rouges concrètes.

Erreur n°2 : essayer de lancer go tool cover sans avoir créé coverage.out.
go tool cover lit un profil, il ne lance pas les tests. Donc si le fichier est absent ou obsolète, soit vous obtiendrez une erreur, soit vous analyserez le monde d’hier. La discipline est simple : d’abord go test -coverprofile=coverage.out, ensuite seulement go tool cover…

Erreur n°3 : percevoir les lignes rouges comme un signal pour « tout réécrire ».
Rouge signifie « non exécuté par les tests », pas « cassé ». Parfois, c’est le signal d’ajouter un seul test pour un cas limite, et c’est tout. Parfois, c’est le signal que la branche n’est pas utile et qu’il faut la supprimer.

Erreur n°4 : chercher à atteindre 100% de couverture à tout prix et écrire des tests absurdes.
On peut écrire un test qui appelle simplement des fonctions sans rien vérifier, et cela « fait souvent monter les pourcentages ». Mais un tel test détecte presque aucun bug et crée un faux sentiment de sécurité. La couverture est un indice de « où regarder », et la qualité du test, ce sont vos vérifications (want/got) et des scénarios clairs.

Erreur n°5 : oublier les branches d’erreur et les retours anticipés.
Ce sont souvent les vérifications d’erreur qui restent non couvertes. Résultat : le « chemin heureux » est vert, et la moindre panne transforme le programme en surprise. Si le HTML affiche en rouge if err != nil { return … }, c’est généralement un bon candidat pour un test séparé qui crée une entrée erronée et vérifie que l’erreur est gérée comme prévu.

1
Mission
Go SELF, niveau 31, leçon 2
Bloqué
Résumé des fonctions
Résumé des fonctions
1
Mission
Go SELF, niveau 31, leçon 2
Bloqué
Branche non couverte
Branche non couverte
1
Mission
Go SELF, niveau 31, leçon 2
Bloqué
Objectif de couverture
Objectif de couverture
1
Mission
Go SELF, niveau 31, leçon 2
Bloqué
Set et Count
Set et Count
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION