mars
2010
Il existe plusieurs outils de mesure de la couverture de code en Java, dont certains open source. J’ai récemment été amené à comparer le fonctionnement des plus connus d’entre eux, et je vous livre ici les résultats bruts de ce comparatif. Je tenterai certainement une analyse dans un prochain billet.
Tout d’abord, quelques notions de base.
Les différentes métriques de couverture de code
Je vous laisse lire l’article de Wikipedia (plus complet en EN) si ça vous intéresse, mais sachez que les principales métriques utilisées (et utiles) sont :
- couverture des instructions (!= couverture de ligne)
- couverture des branches (if/else, try/catch/finally, …)
- couverture des expression booléennes (ou conditions)
Méthodes de mesure
Pour mesurer la couverture de code en Java, il faut un moyen de détecter qu’on est passé sur telle ligne/instruction/branche et pas sur une autre. Il existe plusieurs méthodes :
- L’utilisation des API de profiling de la JVM (JVMDI/PI)
- L’instrumentation du bytecode
- L’instrumentation du code source
Passons très vite sur la première méthode. Aucun des outils de mon comparatif ne l’utilise. Son principal défaut semble être le surcoût au niveau des performances (overhead).
Reste donc les 2 méthodes d’instrumentation. L’instrumentation, c’est le fait d’enrichir le programme original avec des instructions supplémentaires. Ces instructions vont être les témoins que l’on est bien passé à cet endroit du programme. Schématiquement, pour mesurer la couverture des lignes de code, il suffit d’ajouter après chaque ligne du programme original un petit bout de code qui va dire « la ligne XXX a été exécutée ». Ce bout de code va stocker son information en mémoire ou dans un fichier, et à la fin, il suffit de collecter les données et de générer un beau rapport.
L’instrumentation du code source
L’instrumentation du code source va réellement modifier le code du programme avant de le compiler et de l’exécuter.
Exemple (schématique) :
Avant instrumentation :
return a + b;
}
Après instrumentation :
entering_method("addition");
int tmp = a + b;
statement(34); //34 = numero de ligne dans le programme original
return tmp;
}
N.B. : Je ne sais pas réellement ce qui est ajouté comme code, sachant que Clover est closed-source, donc ce n’est qu’indicatif.
L’instrumentation du bytecode
L’instrumentation du bytecode consiste à manipuler le code Java compilé (le fichier .class) pour y ajouter les instructions de « trace ». Le principe est donc le même que pour l’instrumentation de code source, avec les différences suivantes :
Avantages :
- pas besoin de posséder les sources du programme (mais dans ce cas on aura que la couverture des méthodes, pas des lignes)
- pas besoin de recompiler le programme, on modifie directement le .class
Inconvénients :
- le bytecode n’est pas exactement l’image fidèle des lignes de code. Le compilateur effectue des optimisations qui peuvent rendre difficile de distinguer l’exécution de lignes de code consécutives. Si le code est compilé avec l’option debug, il est quand même possible de « deviner » la ligne de manière assez fiable
Ne vous inquiétez pas, une synthèse devrait venir, mais j’ai encore 2-3 tests à mener pour être exhaustif…
Stay tuned
Je ferais mieux de relire deux avant de poster :aie:
@Baptiste
Comme il le dit en intro, une analyse devrait suivre … il y a plus qu’à attendre.
Article très intéressant
Par contre, une petite conclusion serait bienvenue pour expliquer ce qu’on peut sortir de ces différents tests.