1 / 62

Pratique des tests logiciels

Pratique des tests logiciels. Introduction. Activité aussi vieille que le développement Souvent négligée et peu formalisée Considérée (à tort) comme moins « noble » que le développement Coût souvent > 50% du coût total d’un logiciel Très peu enseignée. Idées fausses sur les tests (1/2).

Download Presentation

Pratique des tests logiciels

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Pratique des tests logiciels

  2. Introduction • Activité aussi vieille que le développement • Souvent négligée et peu formalisée • Considérée (à tort) comme moins « noble » que le développement • Coût souvent > 50% du coût total d’un logiciel • Très peu enseignée

  3. Idées fausses sur les tests (1/2) • Il faut éliminer tous les défauts • Doit-on tester le cas où l’automobile roule à 500 km/h ? • L’amélioration de la fiabilité est proportionnelle au nombre de défauts corrigés • Il reste un défaut dans une fonction toujours utilisée … • Je programme sans erreur, ce n’est pas la peine de tester …

  4. Idées fausses sur les tests (2/2) • L’amélioration de la fiabilité est proportionnelle au taux de couverture du code par les tests • Évaluer la qualité d’un logiciel, c’est estimer le nombre de défauts résiduels • Croire que c’est simple et facile • Croire que cela n’exige ni expérience, ni savoir-faire, ni méthodes

  5. Juste un exemple 232 + 232 Faire tous les tests  0,5 milliard d’années ! (pour toutes les valeurs) En phase de test, nous sommes toujours face à l’explosion combinatoire

  6. Les différentes sortes de tests • Tests unitaires • On teste chaque fonction de chaque module (tests « boîte blanche » sur les instructions) • Tests d’intégration • On teste les interfaces entre modules (tests « boîte blanche » sur les interfaces, tests « boîte noire » sur les instructions) • Tests de validation • On teste les fonctionnalités du logiciel (tests « boîte noire »)

  7. Positionnement des types de tests

  8. Graphe de contrôle d’un programme • Tout programme peut se représenter sous forme de graphe où : • Les nœuds sont les instructions • Les arcs sont les branchements • Exemple : Un if-then-else

  9. Les types de nœuds du graphe • Il y a trois types de nœuds : • Les nœuds « fonction » (toute instruction est une fonction) matérialisés par : • Les nœuds « prédicatifs » (représentant une condition) matérialisés par : • Les nœuds « de regroupement » (qui sont vides) matérialisés par : f c

  10. Programmation structurée (1/3) • Si l’on examine tous les graphes de 1 à 4 nœuds (il y en a 15), seuls 7 sont pertinents car les autres n’ont pas de nœuds fonction (il n’y a donc pas d’instruction !) • Ces 7 graphes sont à l’origine de la programmation structurée

  11. Programmation structurée (2/3) • En effet, on a : • L’instruction : a = b; par exemple • La séquence : a = b; c = d; • Remarque : correspond à la composition de fonctions • Les alternatives : • If-then • If-then-else • Les itératives : • While-do • Do…while (ou repeat…until) • Do-while-do (test de « milieu » de boucle)

  12. La programmation structurée (3/3) • On remarque que : • Il n’y a pas le « case » (switch) • C’est un confort syntaxique pour exprimer des cascades de if-then-else imbriqués • Il n’y a pas de boucle « for » • La boucle «for » n’est pas une vraie boucle

  13. Programme structuré • Un programme structuré est donc : • Un programme qui ne possède qu’un point d’entrée et un point de sortie • Constitué à partir des 7 formes de bases (appelées structures premières) • Tel que pour chaque nœud il existe un chemin reliant l’entrée à la sortie

  14. Nombre cyclomatique(1/4) • À partir du graphe de programme on peut calculer le nombre cyclomatique (Mc Cabe-1976) V(g) tel que : • V(g) = e – n + 2 (e : edge, n : node) • Le nombre cyclomatique représente : • Le nombre de chemins linéairement indépendants dans un graphe fortement connexe • Le nombre de décisions + 1 prises dans un programme (i.e. le nombre de nœuds prédicatifs + 1)

  15. Nombre cyclomatique(2/4) • Un graphe est fortement connexe si : •  ni et nj, deux nœuds du graphe,  un chemin reliant ni et nj • On remarque qu’un programme bien structuré n’a pas un graphe fortement connexe car il n’y a pas de chemin reliant la sortie à l’entrée ! (on ajoute donc cet arc fictif) • Le nombre de chemins linéairement indépendants correspond au nombre de régions du plan délimitées par le graphe quand les arcs ne se recoupent pas.

  16. Nombre cyclomatique(3/4) • Exemple    V(G) = 3 (donc 2 décisions)

  17. Nombre cyclomatique(4/4) • Quelle valeur maximum ? • On considère généralement que le nombre cyclomatique doit être inférieur à 10 dans chaque sous-programme • Remarque importante • Le nombre cyclomatique ne mesure que la complexité structurelle statique

  18. Exercice 1 // Radiation d'un abonne void Bibliotheque::RadierAbonne(int code_ab) { system("cls"); POSITION pos=la_liste_abonne.GetHeadPosition(); while (pos) { if (code_ab==la_liste_abonne.GetAt(pos).ObtenirCode()) { if (la_liste_abonne.GetAt(pos).ObtenirDateRadiation()==0) { if (la_liste_abonne.GetAt(pos).Nb_Exemp_Emprunte()==0) { la_liste_abonne.GetAt(pos).RadierAbonne(); printf("Nouveaux renseignements sur l'abonne : \n\n"); la_liste_abonne.GetAt(pos).AfficherAbonne(); printf("\n\n"); printf("\t\tAppuyez sur ENTREE pour revenir au menu"); fflush(stdin); getchar(); system("cls"); return; } else { printf("Cet abonne doit rendre des exemplaires\n\n\n"); return;} } else {printf("Cet abonne est deja radie \n\n");} return; } else {(void)la_liste_abonne.GetNext(pos);} } printf("Cet abonne n'existe pas \n\n\n"); } Faire le graphe de contrôle et calculer le nombre cyclomatique de cette fonction C++

  19. Exercice 2 • Quel est l’ensemble minimum de tests à élaborer pour tester unitairement la fonction RadierAbonne ? • On suppose évidemment que toutes les fonctions appelées ont déjà été testées unitairement • La fonction GetNext met à jour son argument (pos)

  20. Les effets néfastes d’une programmation non structurée Le graphe de gauche est réductible car il n’est constitué que de formes de base de la programmation structurée (ev(g)=1). Celui de droite n’est pas un programme structuré (le goto au milieu). Il n’est plus réductible ! (ev(g) = 12) Ev : complexité effective (en réduisant à 1 nœud les constructions de la programmation structurée)

  21. Complexité et nombre de chemins (1/3) V(G) = 3 Nbre de chemins = 3 V(G) = 4 Nbre de chemins = 3n !

  22. Complexité et nombre de chemins (2/3) Et s’il y a des dépendances fonctionnelles entre blocs … on devrait effectivement tester tous les chemins ! x = 0 y = 5/x

  23. Complexité et nombre de chemins (3/3) • Quelques remarques • Ajouter un « if-then-else » dans une fonction multiplie par 2 le nombre de chemins • Les tests ne détectent pas l’absence de défauts • On peut couvrir tous les arcs du programme et ne pas détecter tous les défauts (voir le transparent suivant)

  24. Défauts et couverture C1  Couverture C1 à 100% mais sans jamais exécuter le chemin de droite  Ce genre de problème se répète entre Cn et Cn+1, n …

  25. Les remèdes (1/2) • Au niveau du développement • prendre des précautions : • Tester systématiquement les divisions par zéro • Tester systématiquement le retour des appels « systèmes » • (malloc/new retournant NULL par exemple en C/C++ !) • Instrumenter le code (au moins pour le mode « debug ») • En C/C++ : utiliser la macro « assert », par exemple :double racineCarree (double x){double resultat; assert(x>=0); //algo assert(resultat * resultat==x); //Pas si simple à cause des problèmes d’arrondis ! return(resultat);} • Ajouter des niveaux de trace (les débogueurs ne suffisent pas !)

  26. Les remèdes (2/2) • Au niveau des tests (unitaires) • Partitionner l’ensemble des valeurs d’entrée pour chaque fonction • Éliminer les cas impossibles(non pas du point de vue utilisateur, car il peut toujours faire des erreurs, mais du point de vue logique) • En déduire le jeux de tests pour chaque fonction • Si la combinatoire est trop grande alors générer les cas automatiquement (ce qui requiert en général le développement d’un outil sauf si l’on dispose d’un « macro-générateur » très général : m4 de gnu par exemple)

  27. Exemple de partitionnement • Soit une fonction f(int i) définie dans l’intervalle fermé [1..99]. Combien de tests doit-on faire ? (en supposant qu’il n’y a pas de cas particulier dans l’intervalle considéré) • On va tester pour : • f(0) • f(1) • f(k), k  [2..98] (1 seul test) • f(99) • f(100) Soit 5 tests

  28. Testabilité (1/2) • Facteurs de bonne testabilitéIls relèvent en général de la qualité de la conception : • Architecture simple et modulaire (forte cohésion d'un composant) • Abstraction à travers les interfaces (faible couplage des composants) • Politique bien définie de traitement des erreurs

  29. Testabilité (2/2) • Facteurs de mauvaise testabilité • Très fortes contraintes de temps et d'espace • Forte intégration des traitements • Contraintes et attributs non classés • Architecture construite par addition de fonctions • Longue chaîne de traitement

  30. Exemple d’architecture modulaire

  31. Pilotes et souches (1/4) • Comme on le voit sur le schéma précédent, un module n'est pas un programme isolé. Il sera souvent nécessaire de mettre en place (simuler) un environnement pour tester unitairement un composant. • Ceci représente une charge supplémentaire de développement, qui doit être planifiée, car l'environnement mis en place pour chacun des composants à tester unitairement ne fait pas partie de la livraison.

  32. Pilotes et souches (2/4) • Ceci se traduira par le schéma suivant : Jeux d’essai Résultats Pilote Interface Module à tester Souche Souche Souche

  33. Pilotes et souches (3/4) • Le rôle du pilote est de : • Lire les données de test • Les passer au module à tester • Afficher/Imprimer les résultats • Les souches simuleront la logique de comportement. En général elles se contenteront de retourner une valeur fixe conforme aux paramètres passés.

  34. Pilotes et souches (4/4) Plus on aura respecté les principes de forte cohésion et de faible couplage, en conception, plus l'écriture des pilotes et des souches devrait être simplifié.

  35. Tests d'intégration • Les modules ayant été testés unitairement, pourquoi faire des test d'intégration ? • Afin de tester les interfaces réelles entre modules et ainsi valider la conception préliminaire du logiciel.

  36. Les stratégies d’intégration • Le big-bang (tous les modules ensembles) • Par lots fonctionnels (par sous-ensembles de modules) • Incrémental (module par module) : • Démarche descendante (les pilotes d'abord) • Démarche ascendante (les souches d'abord) • Démarche mixte

  37. La stratégie du big-bang • Tous les composants sont assemblés en même temps et le logiciel est testé dans son intégralité. Le chaos est garanti • Les erreurs sont très difficiles à localiser • Les tests ne peuvent être préparés à l'avance • Difficulté de planification • Risque d'entrer dans une boucle sans fin de correction/apparition d'erreurs

  38. L'intégration par lots fonctionnels • Cette stratégie est très liée à l'architecture fonctionnelle du logiciel • Les lots doivent être très cohérents et avec peu de dépendances entre eux • Le développement peut être progressif et planifié

  39. La stratégie incrémentale • C'est l'antithèse du big-bang • Le logiciel est construit et testé par petits morceaux. Les erreurs sont donc plus faciles à localiser et à corriger • Les interfaces sont testées plus complètement et précisément • Une approche systématique des tests peut être employée

  40. La stratégie incrémentale descendante (1/2) • Regrouper et intégrer d'abord les composants de plus haut niveau et simuler les composants de plus bas niveau • Avantages : • Les défauts de structure sont détectés très tôt • L'architecture générale du logiciel est mise en évidence rapidement • Les mêmes jeux de tests peuvent être réutilisés sur plusieurs étapes d'intégration et même en validation (pour certains) • La charge de travail est mieux répartie • Moins de pilotes à mettre en œuvre

  41. La stratégie incrémentale descendante (2/2) • Inconvénients : • La logique des souches doit être élaborée. Elles doivent retourner au composant à tester des valeurs qui correspondent aux différents contextes d'appels • Les composants de bas niveau ne sont testés qu'à la fin alors que leurs interfaces peuvent être délicates (interfaces avec le matériel par exemple) • Tests incomplets si la logique des souches est difficile à simuler

  42. La stratégie incrémentale ascendante (1/2) • Regrouper et intégrer les composants de plus bas niveau (les souches) d'abord • Les pilotes sont simulés • Avantages : • Facilité de localisation des défauts du composant intégré • Les données de tests sont plus faciles à définir

  43. La stratégie incrémentale ascendante (2/2) • Inconvénients : • Il est plus difficile de déterminer les résultats des tests (pas de composant reflétant les fonctionnalités de haut niveau) • Les jeux de tests ne sont réutilisables ni pour les étapes suivantes d'intégration ni en validation car trop spécifiques • Les composants les mieux testés sont les composants de bas niveaux qui ne sont pas toujours les plus complexes

  44. La stratégie incrémentale mixte (1/2) • Les démarches descendantes et ascendantes sont combinées en fonction des critères suivants : • Permettre de simplifier la mise en œuvre des tests • Intégrer les composants réutilisables en premier (du moins très tôt) • Les composants qui exigent l'utilisation de la machine cible sont intégrés dans les dernières étapes • Les composants critiques (haut niveau de contrôle, criticité des performances, …) doivent être intégrés le plus tôt possible

  45. La stratégie incrémentale mixte (2/2) • Il s'agit de minimiser les inconvénients tout en maximisant les avantages. • Ceci exige une forte expérience du chef de projet et une forte compétence des équipes.

  46. Critères de choix de la stratégie (1/3) • Préparation des tests : • Optimiser le nombre de tests • Faciliter la réalisation des tests • Optimiser le nombre de pilotes et souches • Mise en œuvre des tests : • Diminuer leur nombre et leur complexité • Faciliter la localisation des défauts • Minimiser l’utilisation de la machine cible (car elle peut être lourde à mettre en œuvre)

  47. Critères de choix de la stratégie (2/3) • Aspects gestion de projet : • Minimiser la taille des équipes et diminuer la complexité organisationnelle • Faciliter le lissage de la charge, des affectations • Intégrer dès que possible (minimisation des risques) : • les modules devant être fortement testés • les modules à forte probabilité de défauts • les modules à fonctionnalités les plus critiques (vitales et centrales pour le système)

  48. Critères de choix de la stratégie (3/3) • Le plan d'intégration, élaboré durant la phase de conception préliminaire, doit être suivi : • Il définit la stratégie dominante d'intégration et l'ordre dans lequel les composants ou éléments doivent être intégrés. • Il conditionne donc les priorités de développement et de tests unitaires sur chacun des constituants.

  49. Le problème spécifique des IHM (1/7) • Généralités • Élaboration des spécifications de l’IHM

  50. Le problème spécifique des IHM (2/7) • Recommandations de développement • prendre en compte les métiers des utilisateurs (profils, processus métiers) • Élaborer des cas d’utilisation très en amont du cycle de vie • Associer étroitement les futurs utilisateurs à la validation de la maquette et/ou du prototype • Choisir un outil de construction d’IHM qui utilise, si possible, le même langage de programmation que le reste de l’application (sinon, très souvent, de sérieux problèmes d’intégration surviennent)

More Related