La couverture de code (en anglais code coverage) est une mesure utilisée en génie logiciel pour décrire le taux de code source testé d'un programme. Ceci permet de mesurer la qualité des tests effectués.
Car plus un programme est bien testé, moins il est soumis aux bugs.
La mesure de ce taux implique souvent l'utilisation de tests unitaires.
Il y a de nombreuses méthodes pour mesurer la couverture de code, Les principales sont :
La couverture des chemins implique à la fois la couverture des instructions et la couverture des points de tests.
La couverture des instructions n'implique pas la couverture des points de tests.
Car plus un programme est bien testé, moins il est soumis aux bugs.
La mesure de ce taux implique souvent l'utilisation de tests unitaires.
Il y a de nombreuses méthodes pour mesurer la couverture de code, Les principales sont :
- Couverture des fonctions (Function coverage) - Chaque fonction dans le programme ont-elles été appelée?
- Couverture des instructions (Statement Coverage) - Chaque ligne du code a-t-elle été exécutée et vérifiée ?
- Couverture des points de tests (Condition Coverage) - Chaque point d'évaluation (tel que le test d'une variable) a-t-il été exécuté et vérifié ? (Le point de test teste-t-il ce qu'il faut ?)
- Couverture des chemins d'exécution (Path Coverage) - Chaque parcours possible (par exemple les 2 cas vrai et faux d'un test) a-t-il été exécuté et vérifié ?
La couverture des chemins implique à la fois la couverture des instructions et la couverture des points de tests.
La couverture des instructions n'implique pas la couverture des points de tests.
Pour mieux comprendre les choses, je vais monter la différence entre Couverture des instructions (Statement Coverage), Couverture des points de tests (Branch Coverage) et Couverture des chemins d'exécution(Path Coverage).
Pour cela on va utiliser le bout de code suivant:
public int returnInput(int input, boolean condition1, boolean condition2, boolean condition3) {
int x = input;
int y = 0;
if (condition1)
x++;
if (condition2)
x--;
if (condition3)
y=x;
return y;
}
int x = input;
int y = 0;
if (condition1)
x++;
if (condition2)
x--;
if (condition3)
y=x;
return y;
}
Couverture des instructions
Afin d'exécuter toutes les instructions, nous devons faire seulement un seul cas de test qui fixerait toutes les conditions à vrai, dans ce cas chaque ligne du code (déclaration) va être touché.
shouldReturnInput(8, true, true, true) - 100% instructions couvertes.
Mais seulement la moitié des branches sont couvertes et un seul chemin.
Couverture des points de tests
Vous pouvez visualiser que chaque bloc de test "if" contient deux branches (une branche vrai et une autre fausse). Ainsi, il apparaît clairement que le cas de test ci-dessus suit seulement la branche vraie de chaque "if". Donc dans ce cas seulement 50% des branches sont couvertes.
Afin de couvrir 100% des branches, nous aurions besoin d'ajouter le cas de test suivant:
shouldReturnInput(8, false, false, false) Avec ces deux cas de test que nous avons fait maintenant on aura 100% des branches couvertes
Couverture des chemins d'exécution
Néanmoins, il y a encore un concept de couverture de chemin. Afin de comprendre la couverture de chemin, c'est mieux de visualiser le code ci-dessus sous la forme d'un arbre binaire:
Comme vous le voyez probablement les deux cas de test ci-dessus ne concernent que deux chemins (true, true , true) et (false, false, fasle) alors qu'en fait il y a 8 chemins distinctes:
t => true
f => false
t -t -t - couvert avec le cas de test 1
t -t -f
t -f -t
t -f -f
f -t -t
f -t -f
f -f -t
f -f -f - couvert avec le cas de test 2
t -t -f
t -f -t
t -f -f
f -t -t
f -t -f
f -f -t
f -f -f - couvert avec le cas de test 2
Donc pour que vous auriez une couverture de chemins à 100% vous devrez remplir tous les cas possible.