Les informations utilisées dans la conception des tests sont rassemblées à partir de nombreux endroits : modèles de
conception, interfaces de classificateur, diagrammes d'état-transition et le code lui-même. A un moment donné, ces
informations de document source doivent être transformées en tests exécutables :
-
entrées spécifiques données au logiciel testé
-
configuration matérielle ou logicielle particulière
-
initialisation à un état connu
-
résultats spécifiques attendus
Il est possible de passer directement d'informations de document source à des tests exécutables mais il est souvent
utile d'ajouter une étape intermédiaire. Dans cette étape, les idées de test sont écrites dans une liste d'idées de test, qui sert à
créer des tests exécutables.
Une idée de test (parfois appelée exigence de test) est une brève description d'un test qui pourrait être réalisé.
Comme exemple simple, considérons une fonction qui calcule une racine carrée et trouvons quelques idées de test :
-
donner un nombre qui est à peine inférieur à zéro en tant qu'entrée
-
donner un zéro en tant qu'entrée
-
tester un nombre qui est une racine parfaite, comme 4 ou 16 (le résultat est-il exactement 2 ou 4 ?)
Chacune de ces idées peut être facilement convertie en test exécutable avec des descriptions exactes des entrées et
résultats attendus.
Cette forme intermédiaire moins spécifique présente deux avantages :
-
les idées de test sont davantage révisables et compréhensibles que des tests complets ; il est plus facile d'en
comprendre le raisonnement
-
les idées de test soutiennent des tests plus puissants, comme décrit plus bas sous l'intitulé Conception de tests à l'aide de la liste
Les exemples de racine carrée décrivent tous les entrées, mais les idées de test peuvent décrire n'importe lequel des
éléments d'un test exécutable. Par exemple, "impression vers une LaserJet IIIp" décrit un aspect de l'environnement de test à utiliser pour un test, au même titre que
"test avec une base de données pleine". Toutefois, ces idées de test sont incomplètes : Imprimer quoi avec
l'imprimante ? Faire quoi avec cette base de données pleine ? Toutefois, elles assurent que les idées
importantes ne soient pas oubliées ; ces idées seront décrites de façon plus détaillée plus tard dans la conception du
test.
Les idées de test sont souvent basées sur des modèles de défauts ; notions de quelles fautes sont plausibles dans un
logiciel et comment ces fautes peuvent être le mieux mises à jour. Par exemple, considérons les frontières. Il est
prudent de penser que la fonction racine carrée peut être implémentée comme suit :
double sqrt(double x) {
if (x < 0)
// signal error
...
Il est également plausible que le < peut être mal saisi comme <=. Les gens font souvent ce genre
d'erreur, cela vaut donc la peine de vérifier. La faute ne peut pas être détectée avec X avec la valeur
2, car l'expression erronée (x<=0) et l'expression correcte (x<0) prendront la même branche
de l'instruction si. De même, la faute ne sera pas trouvée si on donne à X la valeur -5. La seule
façon de la trouver est de donner à X la valeur 0, qui justifie la deuxième idée de test.
Dans ce cas, le modèle de faute est explicite. Dans d'autres cas, il est implicite. Par exemple, chaque fois qu'un
programme manipule une structure liée, il est bon de la tester par rapport à une structure circulaire. Il est possible
que de nombreuses fautes puissent mener à une mauvaise gestion de la structure circulaire. Pour les besoins du test, il
n'y a pas besoin de les énumérer, il suffit de savoir qu'un certain nombre de fautes sont suffisamment probables pour
que le test vaille la peine d'être exécuté.
Les liens suivants fournissent des informations sur comment trouver des idées de test à partir de différents types de
modèles de faute. Les deux premiers sont des modèles de faute explicites ; le dernier utilise les implicites.
Ces modèles de faute peuvent s'appliquer à de nombreux produits différents. Par exemple, le premier décrit que faire
des expressions booléennes. De telles expressions peuvent être trouvées dans le code, dans des conditions de garde,
dans des diagrammes d'état-transition et diagrammes de séquence, et dans des descriptions en langue naturelle de
comportements de méthode (comme vous pouvez trouver dans une API publiée).
Il est parfois également utile d'avoir des conseils pour des produits spécifiques. Voir Instructions relatives au produit : Idées de test pour diagrammes d'état-transition et
diagrammes de flux.
Une liste d'idées de test particulière peut contenir des idées de test provenant de nombreux modèles de faute, et ces
modèles de faute peuvent être dérivés de plusieurs produits.
Supposons que vous concevez des tests pour une méthode qui recherche une chaîne dans un ensemble séquentiel. Elle peut
respecter ou ignorer la casse dans sa recherche, et elle renvoie l'index des premiers résultats trouvés ou -1 s'il n'y
a aucun résultat.
int Collection.find(String string,
Boolean ignoreCase);
Voici quelques idées de test pour cette méthode :
-
résultat trouvé en première position
-
résultat trouvé en dernière position
-
aucun résultat
-
deux résultats ou plus trouvés dans l'ensemble
-
la casse est ignorée ; résultat trouvé mais ne correspondrait pas si la casse était respectée
-
la casse est respectée ; une correspondance parfaite a été trouvée
-
la casse est respectée ; une chaîne qui aurait correspondu si la casse était ignorée est laissée de côté
Il serait simple d'implémenter ces sept tests, un pour chaque idée de test. Toutefois, des idées de test différentes
peuvent être combinées dans un seul test. Par exemple, le test suivant satisfait les idées de test 2, 6 et 7 :
Création : collection initialisée à ["dawn", "Dawn"]
Invocation : collection.find("Dawn", false)
Résultat attendu : la valeur renvoyée est 1 (ce serait 0 si "dawn" n'était pas ignoré)
Faire des idées de test non spécifiques facilite leur combinaison.
Il est possible de satisfaire toutes les idées de test en trois tests. Pourquoi trois tests qui satisfont sept idées de
test seraient meilleurs que sept tests séparés ?
-
Lorsque vous créez un grand nombre de tests simples, il est courant de créer un test N+1 en copiant le test N et de
le peaufiner juste ce qu'il faut pour satisfaire la nouvelle idée de test. Le résultat, notamment dans des
logiciels plus complexes, est que le test N+1 mettra le programme à l'épreuve pratiquement de la même façon que le
test N. Il prend presque exactement le même chemin d'accès à travers le code.
Un plus petit nombre de tests, chacun satisfaisant plusieurs idées de test, ne permet pas une approche "copier et
affiner". Chaque test sera d'une certaine façon différent du dernier, mettant le code à l'épreuve de façons
différentes et prenant différents chemins d'accès.
Pourquoi cela est-il mieux ? Si la liste d'idées de test était complète, avec une idée de test pour chaque faute
du programme, peu importerait votre façon de rédiger le test. La liste oublie toujours des idées de test qui
pourraient trouver des bogues. En faisant faire à chaque test des choses différentes du dernier (en ajoutant une
variété en apparence inutile), vous augmentez la possibilité qu'un des tests tombe sur un bogue par hasard. En
effet, des tests plus petits et complexes augmentent la chance que le test satisfasse une idée de test dont vous
ignoriez avoir besoin.
-
Parfois lorsque vous créez des tests plus complexes, des nouvelles idées de test vous viennent à l'esprit. Cela se
produit moins souvent avec des tests simples, parce qu'une grande partie de ce que vous faites est exactement comme
le dernier test, ce qui vous rend moins perspicace.
Toutefois, il y a des raisons pour ne pas créer des tests complexes.
-
Si chaque test satisfait une seule idée de test et le test pour la deuxième idée échoue, vous savez immédiatement
quelle en est la cause la plus probable : le programme ne gère pas une correspondance dans la dernière position. Si
un test satisfait les idées 2, 6, et 7, isoler l'anomalie est plus difficile.
-
Des tests complexes sont plus difficiles à comprendre et entretenir. L'objet du test est moins évident.
-
Les tests complexes sont plus difficiles à créer. Elaborer un test qui satisfait à cinq idées de test prend souvent
plus de temps que d'élaborer cinq tests satisfaisant chacun une idée. De plus, il est plus facile de faire des
erreurs, de pense que vous satisfaites les cinq alors que vous n'en satisfaites que quatre.
Dans la pratique, vous devez trouver un équilibre raisonnable entre la complexité et la simplicité. Par exemple, les
premiers tests auxquels vous soumettez le logiciel (généralement les tests de fumée) doivent être simples, faciles à comprendre et entretenir, et
visant à déceler les problèmes les plus évidents. Les tests qui interviennent plus tard doivent être plus complexes
sans pour autant devenir impossible à entretenir.
Quand vous avez fini un ensemble de tests, il est bon de les vérifier par rapport aux erreurs caractéristiques de la
conception de test abordées dans Concept : Tests développeur.
Une liste d'idées de test est utile pour réviser et inspecter les produits de conception. Par exemple, considérons
cette partie d'un modèle de conception montant l'association entre les classes Service et Employé.
Figure 1 : Association entre les classes Service et Employé
Les règles de création d'idées de test d'un tel modèle vous demanderaient de considérer le cas où un service compte
beaucoup d'employés. En parcourant une conception et en vous demandant "que se passerait-il, à ce stade, si le service
avait beaucoup d'employés ?", vous pourriez découvrir des erreurs de conception ou d'analyse. Par exemple, vous
pourriez vous rendre compte que seule un employé peut être transféré à la fois d'un service à un autre. Cela peut poser
un problème si l'entreprise a tendance à réaliser des réorganisations où de nombreux employés doivent être transférés.
De telles fautes, cas où une possibilité est omise, s'appellent des fautes d'omission. Tout comme les fautes,
vous avez probablement omis des tests qui détectent ces fautes dans votre effort de test. Par exemple, voir [GLA81], [OST84], [BAS87], [MAR00], et
d'autres études qui montrent la fréquence à laquelle les fautes d'omission échappent dans le déploiement.
Le rôle des tests dans les activités de conception est abordé de façon plus approfondie dans Concept : Conception pilotée par le test.
La traçabilité est une question de compromis. Sa valeur vaut-elle le
coût de son entretien ? Cette question doit être envisagée dans le cadre de la Tâche : Définir les besoins d'évaluation et de traçabilité.
Lorsqu'une traçabilité est valable, les tests sont conventionnellement tracés jusqu'aux produits qui les ont inspirés.
Par exemple, vous pouvez avoir une traçabilité entre une API et ses tests. Si l'API change, vous savez quels tests
changent. Si le code (qui implémente l'API) change, vous savez quels tests exécuter. Si un test vous étonne, vous
pouvez trouver l'API qu'il doit tester.
La liste des idées de test ajoute un autre niveau de traçabilité. Vous pouvez remonter d'un test jusqu'aux idées de
test qu'il satisfait, et puis des idées de test jusqu'au produit d'origine.
|