Concept: Liste d'idées de test
Une liste d'idées de test est une liste d'idées pour le test, triée par ordre décroissant d'importance et associée à des stratégies de test spécifiques afin de créer des tests exécutables.
Relations
Description principale

Introduction

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.

Que sont les idées de test ?

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.

Conception de tests à l'aide de la liste

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 :

  1. résultat trouvé en première position
  2. résultat trouvé en dernière position
  3. aucun résultat
  4. deux résultats ou plus trouvés dans l'ensemble
  5. la casse est ignorée ; résultat trouvé mais ne correspondrait pas si la casse était respectée
  6. la casse est respectée ; une correspondance parfaite a été trouvée
  7. 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.

Utilisation d'idées de test avant les tests

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é.

Image d'un exemple de modèle de conception

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.

Idées de test et traçabilité

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.