Introduction
Références pour ces notes:
Livres
- The Art of software testing, G.J. Myers, Wiley, 2004 (2nde édition) 1979 (1ère édition).
- Testing object-oriented systems, R.V. Binder, Addison Wesley, 2000.
- A practical guide to testing OO software, J.D. McGregor, D.A. Sykes, Addison Wesley, 2001.
- Le test des logiciels, Xanthakis et al., Hermés, 1998
- Sytematic Black-box Testing, Boris Beizer, Prentice-Hall, 1993
- Lessons learned in Software Testing, Cem Kaner, James Bach andBrett Pettichord, ?, 200?
- Un processus pour les Systèmes d'Informations, Pezziardi et al.,Octo Technology, 2006
- Le test de logiciels, ???, Vuibert, 2003
- Practical Model-based Testing, M.Utting et B.Legeard,Addison-Wesley, 2007
Sites
Listes de diffusion
- software testing
- agile testing
- test driven devlopment
Objectif:
- détecter des erreurs dans un programme;
- célèbre définition de Myers:
Testing is the process of executing a program with the intent of finding errors.
Participe à la validation des programmes:
- valider un programme = vérifier qu'il est conforme à sa spécification;
- autres moyens de validation: vérification et preuve;
- test = moyen de validation principal:
- moins coûteux que la vérification ou la preuve;
- facile à comprendre;
- retour à l'utilisateur immédiat et (plus ou moins) compréhensible;
. Néanmoins ne peut garantir que le programme est exempt d'erreurs:
- n'apporte pas de certitude;
- ne fait qu'augmenter la confiance qu'on porte au programme;
- esprit différent de la vérification (quand une proprieté est prouvée, elle est prouvée !).
Pourtant très coûteux !
- avec la maintenance: 80% du coût total d'un projet (on parle ici dutest de recette ou test système
- un exemple classique adapté de [Myers,Binder]: le Triangle
L'exemple du Triangle
Une version en Ajax du problème du triangle: http://www.testobsessed.com/exercises/triangle.html
Version initiale:
- L'utilisateur rentre trois nombres sensés représenter les longueursdes côtés d'un triangle.
- Le programme répond en indiquant le type du triangle: scalene,isocèle, équilatéral, rectangle ou erreur
Version objet (Binder):
- La classe
Triangle est construite avec trois longueurs
- Elle dispose de méthodes:
isIsocele(), isRectangle(), isScalene()et isEquilateral()
Problème: Donner les cas de test permettant de vérifier et valider le bon fonctionnement de l'application Triangle.
Terminologie
Distinguer panne et erreur :
- une panne (fault) est l'observation d'un comportement incorrect duprogramme testé
- un défaut (defect) est la cause d'une panne. On notera qu'un même défautpeut être à l'origine de plusieurs pannes, et réciproquement qu'unepanne peut-êrte causée par la conjonction de plusieurs défauts (oumême par plusieurs défauts indépendamment les uns des autres)
- une erreur (error) est l'action (ou l'inaction) humaine ayant causél'introduction du défaut dans le logiciel. Une erreur est souventappelée bug mais cela peut induire un subtil effet de déresponsabilisation du programmeur, comme sides leprechauns malins introduisaient des erreurs dans le programmederrière son dos.
Tester révèle des pannes, déboguer enlève les erreurs à l'origine des pannes et en introduit d'autres, d'où l'importance de tester la non-régression donc de disposer d'un mode d'exécution automatisé des tests.
Un état d'esprit
Quelques évidences, pour la plupart issues du [Myers].
Concernant la forme des cas de test:
- inclure dans un cas de test des entrées pour le programme maisaussi le résultat attendu (sortie calculée, émission d'uneexception, impression d'un message, etc);
- toujours déterminer le résultat attendu par rapport à laspécification du programme (pas au code);
- stocker les cas de tests pour pouvoir les exécuter à nouveau;
- soigner la traçabilité des tests.
Concernant le contenu des cas de test:
- vérifier que le programme se comporte bien dans les cas attenduscomme dans les cas invalides. Par exemple, dans le cas du triangle:
- spontanément on vérifiera les cas "équilatéral", "isocèle","quelconque";
- tendance à oublier le cas invalide "pas un triangle";
- mettre en pratique le fait que la probabilité qu'une portion decode contienne des erreurs est proportionnelle au nombre d'erreurdéjà trouvées dans cette portion.
Concernant le processus de test:
- ne jamais tester ses propres programmes (difficile) ;
- examiner très attentivement les rapports de test, les stocker aussi;
- ne jamais partir du principe qu'un test ne trouvera pas d'erreurs.
Enfin: concevoir des cas de tests est (pourvu que le concepteur soit dans le bon état d'esprit) une activité difficile mais créative et intéressante !
Différentes approches
L'exécution sur une machine n'est pas la seule manière de tester un programme.
Test statique
Test «par l'humain», sans machine, par lecture du code:
Principes
- réunions de 4 personnes environ ou plus dont le programmeur et leconcepteur, un programmeur expérimenté, un testeur expérimenté, unmodérateur;
- le but n'est pas de mettre le programmeur sur la sellette mais detrouver des erreurs;
- efficace:
- plus de 50% des fautes sont détectées à ce stade;
- pas forcément des fautes «faciles»;
- complémentaire du test par exécution.
- oblige à écrire du code clair, bien documenté et structuré;
Inspection
lecture du code accompagnée d'une liste des points à vérifier, par ex:
- présence de variables avec des noms très proches;
- expressions booléennes correctes;
- priorité des opérateurs bien comprise;
- évaluation paresseuse des opérateurs bien comprise;
- terminaison des boucles;
- pb de surcharge/redéfinition de méthodes;
revue de code
plus complexe :
- les participants viennent avec des cas de test simples;
- le code est «exécuté» manuellement
Test dynamique
Test par l'exécution du système = cas qui nous intéresse.
Schématisation du test dynamique. Il comporte:
- un testeur (humain);
- pour lancer les tests (fournir les entrées, etc): un pilote oudriver de test (logiciel);
- le problème de l'oracle: comment décider si les résultatsproduits par le test sont bien ceux attendus ? Oracle = capacitéde répondre à cette question (toujours basé sur laspécification);
- problème du critère d'arrêt: comment savoir si on a «suffisamment» testé ? mesures de couverture
Adéquation des tests
Tester complètement (exhaustivement) un logiciel est impossible:
- le nombre de combinaison d'entrées pour les tests est ingérable;
- même s'il était gérable: de toute manière trop coûteux;
- nécessité de trouver un sous-ensemble de l'ensemble des cas de testpossibles qui ont la plus forte probabilité de trouver un maximumd'erreur;
- notion d'adéquation du test d'un logiciel: l'avoir testésuffisamment pour être raisonnablement sûr qu'il se comporte commeil est censé le faire.
L'adéquation peut se mesurer en termes de couverture, qui se mesure par exemple:
- en termes de la proportion de la spécification qui est testée;
- en termes de la proportion du code (de l'implantation) qui estsensibilisée par une suite de tests.
- en termes de la proportion des domaines de valeurs desdonnées en entrée/sortie
Correspond à deux approches de base pour le test:
- test basé sur ce que le logiciel est censé faire: laspécification sert à concevoir l'oracle et les cas detest;
- test basé sur ce que fait réellement l'implantation dulogiciel: la spécification sert à concevoir l'oracle, lecode sert à concevoir les cas de test.
Test fonctionnel
Aussi appelé test en boîte noire, ou test basé sur la spécification.
- aucune connaissance de l'implantation;
- repose exclusivement sur la spécification;
- avantage: permet d'écrire les tests avant le codage;
- inconvénient: l'efficacité du test repose sur la qualité de laspécification (complète et compréhensible pour le concepteur destests).
Le Modèle de base est la fonction caractérisant une relation entre des entrées et des sorties.

Tester, c'est sensibiliser le Composant sous Test (Component Under Test d'où CUT), c'est à dire lui fournir des input, et comparer les output réels aux output attendus au moyen d'un oracle
Test structurel
Aussi appelé test en boîte blanche (plus exactement boîte de verre !) ou test basé sur l'implantation:
- connaissance totale de l'implantation;
- avantages:
- possibilité de fixer finement la valeur des entrées poursensibiliser des chemins particuliers du code;
- critères de couvertures divers et précis.
- inconvénient: conception des tests uniquement pour le code déjà écrit.
En pratique :: Combinaison des deux approches, voir la section consacrée aux critères de tests
Triangle magique
Le code, les specs et les tests se vérifient l'un l'autre. Une erreur dans les tests peut avoir trois interprétations différentes :
- les tests sont incorrects : c'est le cas le plus défavorablepuisqu'il induit une confiance infondée dans le logicielproduit. Pour éviter ce cas, les tests doivent être le plussimple possible ;
- le code est incorrect : cas le plus fréquent;
- les specs sont "incorrectes", p.ex. elles spécifient descomportements impossibles (non exécutables), elles sontincohérentes et/ou contradictoires, elles sont incomplètes.

Tests comme spécification
Lors de la mise en oeuvre du développement dirigé par les tests, ceux-ci peuvent être considérés comme une expression formalisée (exécutable) des spécifications, d'où le raccourci: les tests sont la spécification.
Problème: les tests (unitaires) sont écrits par le développeur, donc ils ne peuvent être qu'une vision partiale des spécifications du logiciel. Nécessaire de compléter les tests par de la documentation orientée client.
En fait, l'écriture des tests permet de mesurer la compréhension de la spécification par le testeur. Ce n'est pas la spécification elle-même qui est généralement inaccessible (dans l'empyrée des Idées).
Le test dans le cycle de développement
Cycle en V
Modèle de développement normalisé par la RFA, nouvelle norme V-modell XT (2004). Le principe est d'associer une activité de vérification (test) à chaque phase du cycle de développement du logiciel.
Schématiquement :
Exigences ---------
\ \
\ ---------- Recette
Spéc. /
fonctionnelles------- /
\ \ /
\ ------ Test système
Architecture --- /
\ \ /
\ ----- Test intégration
Conception -- /
\ \ /
\ --- Test unitaire
\ /
+------+ /
| Code |_____/
+------+
Voir B.Marick pour une critique du modèle en V
Ce modèle offre une classification commode des différentes granularités auxquelles s'applique le test. Attention à la rigidité du modèle de développement.
Test unitaire
- test d'une unité logicielle, d'un «module»;
- pour détecter des fautes dans son comportement individuel;
- on ne teste pas les comportements dépendants d'autres unités;
- avant de tester le mur, tester ses briques;
- notion d'unité: dépend du paradigme de programmation utilisé:fonction, procédure, sous-programme, classe, composant, etc.
Test d'intégration
- vérifier qu'un ensemble d'unités coopérent correctement;
- pour détecter des erreurs dans leur inter-opérabilité, la mauvaiseutilisation d'une interface (surtout si interface floue);
- basé sur l'architecture de conception;
- plusieurs approches pour l'intégration:
- non-incrémentale ou big-bang: les modules sont testésunitairement chacun de leur côté; puis on les assemble et onteste le tout d'un coup;
- incrémentale: on assemble un module déjà testé avec un module pasencore testé, puis on teste leur combinaison. Encore deuxapproches: bottom-up et top-down.
- pour simuler les modules non encore testés ou non disponibles: «bouchons» ou stubs.
Test système
Sur une application complètement intégrée ds son environnement.
- test de montée en charge;
- stress de l'application;
- ...
Et aussi...
- test de régression (ou non-régression) : nouveau test dusystème après une modification pour vérifier qu'elle n'apas apporté d'autres fautes. En pratique, les tests fonctionnelsd'une version
n sont des tests de non-régression pour laversion n+1 ;
- smoke test: tests "primitifs" pour vérifier la bonne marche d'unsystème, le nom vient de l'époque des constructeurs de hardware: sion branche et que çane fait pas de fumée, c'est que le test estréussi.
Test de recette
Ou test d'acceptation, (ou User Acceptance Testing, ou simplement recette) : effectué avec l'utilisateur final pour valider le système produit par rapport aux exigences, pour obtenir son approbation avant la livraison.
Le modèle W
http://www.gerrardconsulting.com/default.asp?page=services/wmodel.html
Raffinement du modèle V pour mettre en avant les différentes activités de test et de vérification des artefacts produits pour le logiciel aux différentes étapes du cycle de développement.
Le V principal est dupliqué par un autre V représentant les différentes activités de V&V ayant lieu au cours du développement:
La branche gauche du W lie à chaque activité de conception des activités d'analyse ou de "test statique":
- exigences: animation des exigences, inspection des scénarios,analyse des modèles métiers
- spécifications: revues
- architecture: prototypage, inspection de code
- conception/codage: analyse statique, revues de code
La branche droite du W lie à chaque activité de construction d'une partie du logiciel final (unité, composant, sous-système, système) une activité de "test dynamique":
- codage/conception: test unitaire
- architecture/intégration continue: test d'intégration
- spécifications/construction système: tests systèmes
- exigences/déploiement: tests d'acceptation
Le modèle Agile
Les méthodes Agiles (Extreme Programming essentiellement) utilisent le test comme moteur du processus de développement afin de:
- réduire les déchets (le travail ne contribuant pas directement àajouter de la valeur au produit final)
- améliorer la qualité du logiciel produit
- maximiser l'adéquation entre les besoins réels du client (ie. pasnécessairement les besoins exprimés formellement) et le logicielproduit. On suppose que les besoins exprimés sont toujourspartiels, partiaux et qu'ils changent.
Ce qui implique de:
- réduire les cycles de développement;
- eXtreme programming: on écrit les tests puis on code (mais il estformellement déconseillé d'utiliser les tests comme spécification!) ;
- [McGregor Sykes] test early, test often, test enough
- tester dès la phase d'analyse;
- processus de développement itératif (analyse a little, design alittle, code a little, test what you can): tester à chaqueincrément;
- soigneusement peser sur ce quoi doit se concentrer l'effort detest (risk analysis), hiérarchisation des tests d'où la méthodedes tests basés sur les risques (James Bach).
- exécuter les tests en permanence sur la base de code réelle:intégration continue (voir aussi test en continu), tous les testssont toujours exécutés sur tous le code en permanence
- donc, les tests doivent être exécutables (ou automatisés) pourdiminuer leur coût: seul subsiste le coût de conception (etd'écriture initiale) des tests.
Résultat: Développement Dirigé par les Tests (Test Driven Development) ou TDD
Tests unitaires et TDD
Technique de développement/conception (les deux sont synonymes en XP)
Principe:
- Ecrire un test
- S'assurer qu'il échoue
- Ecrire le code minimal permettant de réussir le test
- S'assurer qu'il réussit
- Réusiner (refactor) le code pour supprimer les doublons etaméliorer sa testabilité
Mantra:
- Red : la barre de test unitaire est rouge
- Green : la barre de test est verte
- Refactor : le code est amélioré
Intérêt:
- maintien en parallèle des tests et du code, donc on a à dispositionen permanence un ensemble fiable de tests de non-régression
- seul le code testé est produit, ergo seul le code utile est écrit
Autres tests
Ce même principe est appliqué à tous les types de tests:
- on définit pour chaque niveau de granularité adéquat des testspermettant de valider de manière exécutable et formelle que leproduit (l'incrément, le logiciel, le composant)
- différents outils/langages sont utilisés pour définir de manièreadéquate les différents tests: tests systèmes, tests d'acceptation,tests fonctionnels d'IHM...
Comparaisons
Attention, cette comparaison est biaisée en faveur des modèles Agiles
Le coût de correction d'une erreur croît de manière exponentielleen fonction de l'interval de temps séparant la production del'erreur de sa manifestation sous forme d'une panne
B.Boehm, référence ??
Plus les tests sont réalisés/exécutés tôt, plus les erreurs qu'ils sont susceptibles de détecter seront révélées tôt, donc moins elles coûteront cher.
Réduire les cycles de développement: analyse-conception-réalisation-test pour détecter au plus tôt les erreurs, omissions, incompréhensions, et réagir au changement dans les meilleurs délais.
Le test dynamique
Définitions officielles: IEEE (Standard Glossary of Software Engineering Terminology).
Qu'est-ce qu'effectuer un test (dynamique) ?
- déterminer un objectif de test: la propriété à tester;
- choisir une donnée de test: au sens large des valeurs pour lesentrées qui permettent d'amener le programme (l'IUT) dans unétat propice à la vérification de l'objectif(positionnement de ses variables d'états);
- écrire un cas de test: un programme qui amène l'IUT dans cet étatpropice et effectue le test;
- stocker le cas de test ainsi que le résultat attendu: les deuxdoivent être conservés pour pouvoir rejouer les tests;
- exécuter ce cas de test;
- observer et enregistrer les résultats;
- les comparer avec les résultats attendus
Qu'est-ce que tester dynamiquement ?
- Exécuter sur l'IUT une suite de tests;
- Corriger les erreurs révélées par les tests;
- Relancer la suite de tests sur la nouvelle version de l'IUT;
- Évaluer le critère d'arrêt/de couverture;
- Compléter la suite de test si besoin;
- On obtient une version de référence (baseline version);
- Relancer cette suite lors des tests de régression, et dès quebesoin de comparaison avec la version de référence.
besoin d'automatisation du test.
Terminologie
qui teste-t-on ? :: une implantation du système: IUT = Implementation Under Test ou encore SUT = System Under Test
que teste-t-on ? :: une propriété/caractéristique à vérifier: l'objectif de test;
donnée de test :: valeurs spécifiques pour les entrées du programme et pour la simulation de l'environnement (peuvent servir pour plusieurs cas de test);
jeu de test :: ensemble de données de test;
cas de test :: test élémentaire associé à une donnée de test pour un objectif de test donné. Il contient souvent:
- un préambule qui mène l'IUT dans une configuration particulière à la donnée de test;
- un corps de test qui permet de vérifier l'objectif de test;
- un postambule qui ramène par ex l'IUT ds un état permettant d'enchaîner un autre test;
- le résultat attendu;
- le résultat attendu inclut les sorties, le post-état del'IUT, les exceptions levées, les messages générés;
suite de test :: un ensemble de cas de test rassemblés suivant un critère donné (ex: tests de toutes les méthodes d'une classe);
critère d'arrêt :: critère permettant d'évaluer si la confiance apportée par les tests effectués est suffisante; stratégie de test ou critère de sélection: algorithme pour créer des cas de test;
critère d'adéquation :: détermine a posteriori si un cas de test est intéressant, cf test par mutation;
- un test réussit (passes) si les résultats obtenus sont lesrésultats attendue, sinon il échoue (fails);
- en cas d'échec, l'IUT contient une faute (un bout de codeincorrect), causée par une erreur humaine.
Automatisation des test unitaires
Source: xUnit Patterns, Gerald Meszaros, Addison-Wesley, 2007, pp.19-30
Motivation économique: le coût initial d'apprentissage, puis les coûts de construction et maintenance des tests sont justifiés par des gains lors du développement.
Objectifs
Amélioration de la qualité
Les tests sont des spécifications exécutables:
- applicable surtout au TDD: un outil pour comprendre et détailler lefonctionnement de l'application
- attention: ce n'est vrai que si les tests fournissent une bonnecouverture du comportement attendu (ie. de la spécification), cequi suppose des tests manuels et une compréhensions du problème
Les tests automatisés ne détectent pas de pannes, ils servent à les prévenir ! Par contre, ils permettent éventuellement de localiser plus rapidement les défauts à l'origine des pannes, en étant précis et localisés.
Compréhension du SUT
Les tests documentent le code, ce qu'il est sensé faire.
Ils permettent de limiter les risques, en les identifiant au plus tôt et en les levant.
Ils constituent un filet de sécurité pour les développeurs:
- on peut toucher au code sans crainte: si on fait une bêtise, on lavoit tout de suite parce qu'un test échoue
- dans le code légataire, on n'a pas cette sécurité (stratégie derefactoring de code légataire: écrire des jeux de test)
- couplage avec le contrôle de sources: permet de toujours revenir enarrière, éventuellement d'identifier la modification du code ayantintroduit une erreur (eg. voir bisect
Les tests ne doivent pas augmenter les risques: ils doivent être simples, immediats, et tester effectivement le code (attention à l'abus de doubles).
Facilité d'exécution
Les tests doivent pouvoir être exécuté très fréquemment:
- l'exécution doit être totalement automatisés
- chaque tests doit être auto-vérifiants: le tests doit encapsuler son oracle
- tous les tests doivent être reproductibles: pas d'effets de bord,pas de comportement non-déterministe dans le résultat du test
Facilité d'écriture
Les tests doivent être simples à lire et à écrire, et éviter la duplication, le recouvrement dans les comportements qu'ils testent.
- simplicité: pas de flôt de contrôle complexe dans les tests, uneseule vérification par test, chaque test est un cas identifié et unseul
- expressivité: limiter/encapsuler le boilerplate code, définir desbibliothèques spécifiques, pseudo-DSL permettant de comprendreimmédiatement l'objectif d'un test (tension entre DRY/factorisationet nécessité d'autonomie de chaque cas de test)
- séparation des préoccupations:
- séparer le code de test du code de production
- séparer les responsabilités de chaque test
Limiter la maintenance
Les tests doivent être robustes:
- le nombre de tests affectés par un changement doit être réduit
- les tests ne doivent pas dépendre de leur environnement(cf. autonomie): système de fichiers, si possible OS, réseau...