40

9. VALIDATION ET VERIFICATION - …users.polytech.unice.fr/~hugues/GL/chapitre9.pdf · déroulent tout au long du cycle de vie lors de l'approbation des documents intermédiaires

  • Upload
    vuliem

  • View
    222

  • Download
    0

Embed Size (px)

Citation preview

9. VALIDATION ET VERIFICATION

La garantie de la qualité est assurée par les étapes de validation et de vérification. Ces activités se déroulent tout au long du cycle de vie lors de l'approbation des documents intermédiaires et pendant des phases réservées: tests unitaires, intégration, qualification (phases de remontée du cycle de vie en V).

Nous revenons, dans ce chapitre, sur les critères de qualité et quelques métriques permettant de les mesurer; nous définissons précisément les revues et les inspections qui sont garantes de la qualité tout au long du cycle de développement. Nous étudions en détail les méthodes de tests dynamiques pour différents types de logiciels. Nous abordons la problématique de la preuve de programme.

9.1. RETOUR SUR L'ASSURANCE QUALITE La notion de qualité recouvre deux aspects:

- conformité avec la définition, cette notion est contrôlable en cours de fabrication, - réponse à l'attente de l'utilisateur , cette notion est contrôlable à la livraison du produit.

La validation a pour base les besoins que le produit doit satisfaire, et pour fonction la mise en évidence de défauts. Valider c'est répondre à la question : "Faisons nous le bon produit?" La vérification a pour base des définitions précises et non ambiguës consignées antérieurement, elle a pour fonction la mise en évidence d'erreurs. Vérifier c'est répondre à la question "Faisons nous le produit correctement?" On précise la terminologie en accord avec la norme IEEE (Standard glossary of software engineering terminology) Erreur: Commise par le développeur, conduit à un défaut, Défaut: Imperfection dans le logiciel conduisant ou non à une panne, Panne: Comportement anormal d'un programme.

Validation- vérification Anne-Marie Hugues 26/09/2001 9-1

9.1.1. QUALITE: APPROCHE DE MAC CALL Mac Call définit une approche de la qualité, déjà abordée dans le chapitre précédent, à partir de la

définition de caractéristiques externes (facteurs de qualité), internes (critères de qualité), mesurables (métriques).

9.1.1.1. Facteurs de qualité Les facteurs de qualité peuvent être classés en 3 catégories. Les caractéristiques opérationnelles (product operation) conformité aux besoins: le produit fait-il ce que je souhaite? fiabilité: le fait - il correctement dans tous les cas? efficacité: utilise-t-il au mieux le matériel? intégrité: est-il protégé contre les intrusions? a-t-il un niveau de sécurité suffisant? facilité d’emploi : au niveau de l’apprentissage, de la mise en œuvre, de la

préparation des données, de l’interprétation des résultats La capacité d’évolution (product revision) maintenabilité: facilité avec laquelle on peut localiser et corriger les erreurs, souplesse : facilité de modification et d’évolution (adaptation à de nouveaux besoins), testabilité : effort requis pour le tester. L’adaptabilité (product transition) portabilité: peut-on utiliser le logiciel sur une autre machine? réutilisabilité: peut-on réutiliser des parties du logiciel dans d’autres applications, interopérabilité: facilité d’interfaçage avec un autre système (“ouverture”). Les facteurs de qualité peuvent avoir une influence les uns sur les autres. Par exemple les facteurs suivants diminuent l’efficacité: intégrité (nécessité d’introduire des vérifications), facilité d’emploi (nécessité d’introduire des interfaces sophistiqués), maintenabilité (sacrifier l’efficacité pour la lisibilité), portabilité (les structures portables ne sont pas nécessairement les plus efficaces), testabilité, souplesse, réutilisabilité, interopérabilité. Les facteurs suivants diminuent l’intégrité: souplesse, réutilisabilité, interopérabilité.

9.1.1.2. Les critères de qualité Mac Call définit 23 critères perceptibles par l’informaticien et permettant d’évaluer dans quelle mesure les

facteurs de qualité sont atteints. Chaque facteur défini précédemment est mesuré en fonction d’un certain nombre de critères. Chaque critère est évalué par une métrique.

Le schéma ci-dessous donne une description des critères associés aux facteurs qu’ils permettent d’évaluer.

On notera à quel point le critère de modularité est important.

9- 2 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

opérabilité apprentissage communicabilité volume d'E/S taux d'E/S

contrôle d'accès mise en œuvre efficacité mémoire efficacité d'exécution

traçabilité complétude

précision

tolérance aux fautes

cohérence

simplicité

concision

nstrumentation

évolutivité

généralité

auto-description

modularité

ndépendance machine

ndépendance système

communications banalisées

données banalisées

facilité d'emploi

intégrité

efficacité

conformité

fiabilité maintenabilité

testabilité

souplesse

réutilisabilité

portabilité

interopérabilité

9.1.1.3. Quelques métriques associées aux critères de qualité Ces critères de qualité sont exigés dans le plan qualité du projet. Ils ne peuvent toutefois être mesurés qu'a

posteriori grâce à quelques métriques adaptées. On distingue deux types de métriques:

- les métriques reposant sur des mesures objectives et évaluant des caractéristiques internes: taille, complexité du flot de contrôle, cohésion modulaire, couplage intermodules. De nombreuses métriques ont été proposées dans ce domaine. Nous les développons dans ce chapitre, au paragraphe consacré à l'analyse statique de code.

- les métriques permettant d'évaluer des caractéristiques externes et reposant sur des évaluations stochastiques. Une littérature abondante existe sur le sujet, aucune métrique ne prévaut en la matière. Nous citerons à titre d'exemple quelques métriques employées pour définir des critères externes de qualité.

Validation- vérification Anne-Marie Hugues 26/09/2001 9-3

La fiabilité F pourra se mesurer en prenant en compte le temps moyen de réparation, le temps moyen entre deux pannes (mesures stochastiques)...

La facilité d'utilisation prend en compte le nombre d'écrans d'aide (métriques objectives), le nombre de fausses manipulation par jours, le nombre de jours d'apprentissage nécessaires (métrique stochastiques).

La portabilité dépend en particulier du nombre d'instructions dépendant de la cible (mesures objectives) mais également de la manière dont celles-ci sont encapsulées (métrique plus difficile à définir).

Il serait difficile de lister ici les nombreuses métriques qui existent. L'important est de définir dès le plan qualité la façon dont les différents critères exigés seront mesurés et de s'interroger sur la validité de la métrique préconisée.

9.1.1.4. Graphes de Kiviat On pourra récapituler l’ensemble des valeurs mesurées pour les différents attributs choisis pour

caractériser la qualité d’un logiciel sur un graphe de Kiviat. La norme est représentée par la circonférence (rappelons que les normes sont définies dans le plan

qualité). Les valeurs à l’intérieur du cercle respectent les normes; celles à l’extérieur sont hors normes.

norme

mauvais

bon

efficacité complexité

9- 4 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.1.2. PRINCIPES DE L’ASSURANCE QUALITE Il s'agit d'assurer et contrôler la qualité, en mettant en évidence le plus grand nombre de défauts.

L'assurance qualité trouve sa justification technique et économique dans l'étude des erreurs. Le plan qualité définit dès la phase de spécifications fonctionnelles les moyens à mettre en œuvre pour la qualification et les métriques utilisées pour l’évaluer.

La découverte tardive des erreurs (statistiques: plus de 50% en moyenne découvertes en phase d'exploitation) pose un problème aigu quand on sait que le coût de réparation croit exponentiellement avec l'avancée dans le cycle de vie. C'est donc tout au long du cycle de vie que les méthodes de validation - vérification doivent être mises en œuvre bien que la phase de qualification soit la seule phase spécifiquement réservée. Cette activité est présente dans toutes les autres phases que ce soit pendant le déroulement de la phase concernée ou par la planification de l'activité pour les phases ultérieures (cycle de vie en V). L’assurance qualité présente également un intérêt évident du point de vue de la gestion de projet puisqu’elle permet un meilleur contrôle de l’état d’avancement du projet et une meilleure estimation des coûts. Les principaux écueils à son bon déroulement sont le plus souvent:

- prééminence du planning sur la qualité, - sous-estimation des ressources , -par les développeurs (activité jugée marginale) -par les managers (nécessité de prévoir des budgets maintenance et

développement séparés) Le rôle du management est pourtant essentiel dans la définition des objectifs de qualité et l'estimation de

son évolution. Il doit rechercher les moyens les plus appropriés et allouer les ressources adaptées aux moyens retenus.

9.1.3. ASSURANCE QUALITE ET CYCLE DE VIE En phase de spécifications fonctionnelles, il s’agit essentiellement de valider la conformité aux besoins

et de définir le plan qualité. Quelques méthodes peuvent s’avérer utiles dans le dialogue avec l’utilisateur: prototypage maquettage tests de spécification (outil ObjectGeode de Telelogic, http://www.telelogic.com/products) spécifications formelles et preuves examen de documents Le plan qualité et les documents primitifs (cahier des charges, spécifications) permettent au moment de

l’analyse et de l’expression du besoin de définir des intentions. Une lecture critique du plan qualité doit permettre de répondre aux questions suivantes:

- contrôle de la conformité au manuel qualité: les rubriques attendues existent-elles? - contrôle de l’intention: les rubriques permettront elles d’atteindre la qualité souhaitée ( détail des

documents et procédures)? - contrôle du réalisme: les rubriques désignent-elles les moyens nécessaires et obtenus (dénomination

des intervenants, des phases)?

Validation- vérification Anne-Marie Hugues 26/09/2001 9-5

- moyens à mettre en œuvre: Les documents primitifs doivent préciser

- description du système où s’insère le logiciel, interfaces matérielles et humaines, - connaissance des fonctions externes voulues pour le système et leur domaine d’utilisation, - découpage clair de ces fonctions et de leurs communications, - indication par composant et par phase des méthodes et outils prévus et du réalisme de leur mise en

commun, - détermination des performances requises de manière chiffrée et pour des systèmes de référence. - description des facteurs de qualité attendus de manière explicite (valeurs et méthodes), - détermination de la procédure d’acceptation du logiciel, - détermination du contenu de la fourniture: produit, documentation, formation, maintenance, - coût de l’ensemble.

9.1.4. MOYENS DE L’ASSURANCE QUALITE: Il existe deux grandes familles de méthodes pour s'assurer de la qualité d'un produit logiciel: les méthodes

dynamiques et les méthodes statiques. Les méthodes reposant sur l'exécution du programme avec des jeux de données préétablis sont aussi

vieilles que le développement de logiciel; elles regroupent les différents tests dynamiques réalisés essentiellement pendant les phases de vérification (tests unitaires et tests d'intégration) et de qualification.

En phase de vérification on vérifie la conformité aux spécifications fonctionnelles. En phase de qualification, le programme est validé sous différents points de vue: validation du programme par rapport aux performances requises tests de performance tests de capacité de charge validation par rapport aux besoins Béta tests (chez l'utilisateur final) L'examen critique de document est réalisé à travers une lecture statique du document (texte ou code) de

manière individuelle ou collective. Son efficacité a été démontrée dès le milieu des années 70 et a suscité un certain engouement en particulier dans l'utilisation qui en est faite au sein de la méthode CleanRoom d'IBM.[DYE 1992]

La preuve de programme que nous abordons à la fin du chapitre s'apparente aux méthodes statiques, elle

ne nécessite pas une exécution du code avec des jeux de données prédéfinis; toutefois nous verrons qu'elle peut nécessiter l'utilisation d'un démonstrateur automatique de théorème dont les entrées sont les procédures ou programmes à démontrer.

9.2. EXAMEN CRITIQUE DE DOCUMENTS L’examen critique porte sur tout document livrable en interne ou au client, prévu dans le cycle de vie et le

plan qualité. Il vise à fournir un point de vue indépendant de l'auteur du document. Il permet de réduire le coût du produit et fournit des mesures précises pour la gestion de projet. L'examen critique de documents peut se faire selon diverses méthodes, le choix d'une méthode doit prendre en compte les critères suivants:

- pouvoir de détection des défauts et des erreurs,

9- 6 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

- coût, - caractéristiques de l'activité.

Toutes ces méthodes ont quelques caractéristiques communes.

9.2.1. CARACTERISTIQUES COMMUNES Il faut se garder pendant cette activité de porter un jugement de valeur sur l'auteur; il s'agit essentiellement

de critiquer les aspects techniques du document. En particulier, le résultat des inspections ne devrait pas être pris en compte dans l'entretien de fin d'année d'un ingénieur.

L'examen critique de document est utile en validation et en vérification. Les propriétés sont contrôlées par

rapport à des critères objectifs. On examine: - la forme: précision, non ambiguïté, satisfaction des normes définies dans le plan qualité et le plan

projet - le fond: complétude, cohérence, (références imprécises ou inexistantes), - la testabilité et la traçabilité ( conformité par rapport aux documents amont)

L'examinateur doit juger en fonction des bonnes pratiques et des usages et de l'état de l'art du domaine. En vue de la mise en évidence d'erreurs, l'examinateur est amené à reconstituer le raisonnement de l'auteur, s'assurer de sa cohérence, identifier:

- les mauvaises interprétations de documents de référence, - les critères de qualité non observés, - les hypothèses erronées.

A titre indicatif, le coût des inspections peut être évalué en termes de nombre de pages relues par heure. Il

diffère selon les phases cahier des charges 5-10 pages /h, spécifications fonctionnelles 10 pages/h, conception globale 5-15 pages/h, conception détaillée 10 pages/h, code 20-50 lignes/h. La sélection des participants se fait selon certains critères qui diffèrent selon les phases On s’attachera en

particulier à avoir différents points de vue et à faire appel à des compétences multiples. De manière générale il est préférable de choisir les participants en dehors de l'équipe de développement. ils seront ainsi plus objectifs car moins impliqués dans le projet. Il convient ensuite d'attribuer un rôle à chacun., il est bien évident qu'un participant peut éventuellement tenir plusieurs rôles.

9.2.2. QUELQUES METHODES DE RELECTURE OU INSPECTION Différentes organisations sont possibles de la simple relecture personnelle de code à la revue très organisée et formalisée.

Validation- vérification Anne-Marie Hugues 26/09/2001 9-7

9.2.2.1. Auto-correction (Desk-checking) Il s’agit d’une simple relecture personnelle de son travail (code, document..) à l’aide d’une liste de

défauts typiques. La contribution de cette méthode à l’assurance qualité est pratiquement nulle en ce qui concerne les

documents amont, elle est assez faible pour la relecture de code.

9.2.2.2. Lectures croisées (Author-reader cycle) Même méthode que précédemment mais la relecture se fait par un collègue qui recherche les ambiguïtés,

imprécisions, oublis. La contribution de cette méthode à l’assurance qualité reste assez faible en ce qui concerne les documents

amont, elle est plus adaptée à la relecture de code.

9.2.2.3. Revues (Walkthroughs) Il existe différents types de revues qui diffèrent essentiellement par la formalisation plus ou moins forte du

processus. Dans tous les cas l’évaluation se fait par un groupe (10 personnes maximum), la présentation orale est précédée par une lecture préalable du document.

Dans une revue informelle, l’examen est conduit par un lecteur qui résume paragraphe par paragraphe le contenu du document. Il n’y a pas de conduite du débat mais plutôt une discussion informelle. Les problèmes sont évoqués et des solutions envisagées. La contribution de cette méthode à l’assurance qualité est moyenne; l’évaluation est très liée à la prestation du lecteur .

Une revue structurée utilise un cadre plus formel: constitution d’une liste de défauts séparée du document, utilisation d’une liste de défauts typiques (check list), direction des débats par un secrétaire. La contribution à l’assurance qualité s’en trouve améliorée. (bonne) On peut également utiliser la méthode du tourniquet (round robins) Chaque examinateur se voit attribuer un rôle particulier. examen de tel ou tel chapitre uniquement sous tel ou tel point de vue Pendant la discussion la parole est passée à chaque membre à tour de rôle (d’où le titre de round

robins).La contribution à l’assurance qualité est variable et dépend de l’attribution des rôles.

9.2.2.4. Inspections Même principe d’examen collectif mais dans un cadre tout à fait formel .L’inspection d’un document se

fait en trois étapes: préparation: recherche des défauts, cycle de réunions, suivi: vérification des corrections ou nouvelle inspection Les défauts sont recherchés et identifiés avant le débat et un rapport de défauts est rédigé avant la

réunion. Les moyens sont précisés. documents de référence, moyens de travail, documents résultant, liste de défauts typiques,

9- 8 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

formulaires d’inspection (formulaire de description de défaut), Modalités, organisation Les critères de sélection des participants sont précis. Les responsabilités de chacun sont clairement

définies. Les débats sont dirigés par un modérateur. Il prépare les réunions et veille à l’enchaînement des étapes. Il veille pendant la conduite des débats au maintien des objectifs et s’attache à ne pas négliger les facteurs humains. Il préside à la prise de décision.

Le secrétaire enregistre les défauts pendant la réunion et fournit une assistance au modérateur. Mais les solutions aux défauts ne sont jamais discutées. On prend date pour en rediscuter (nouvelle inspection ou simple réunion)

L’auteur fournit une opinion sur chaque défaut considéré. En ce qui concerne les autres inspecteurs (environ 3), différents points de vue sont sollicités par rapport au

cycle de vie (financier en phase amont par exemple, expert en phase de conception ou de codage par exemple).

La décision de confirmation d’un défaut est fondée sur la notion de consensus. Responsabilités Chaque inspecteur est responsable de la qualité du produit final et du respect des principes de qualité

définis dans le plan qualité. Le modérateur est responsable du bon déroulement de la réunion (convocation, tenue, suspension) et de l’enregistrement des défauts (ou de sa direction). L’auteur doit soumettre un document prêt à la date prévue. La direction doit assurer la disponibilité des moyens et ressources et l’indépendance des conclusions des inspections par rapport à la gestion de projet.

Planification et analyse des résultats Pour chaque type de document, dans chaque projet, produire un plan d’inspection décrivant parties à inspecter, dates de début et fin par rapport au plan projet, critères de sélection des inspecteurs (équipe indépendante), types de défauts les plus communs, critères de succès de l’inspection, Ce plan figure partiellement dans le plan qualité. La contribution de cette méthode à l’assurance qualité est indiscutablement la meilleure. La formalisation oblige à planifier et à observer des principes de qualité. On constate une amélioration

rapide des méthodes et du cycle de vie. La formalisation a également une influence positive sur la communication et la formation.

9.2.3. CONCLUSION L’examen critique de document permet de vérifier tout au long du cycle de vie que le réalisé est conforme

aux intentions et en particulier sur les documents amont, avant l’écriture du code. Les méthodes d’analyse statique de code que nous décrivons plus loin définissent des mesures objectives

permettant d’évaluer la qualité du code.

Validation- vérification Anne-Marie Hugues 26/09/2001 9-9

9.3. ANALYSE STATIQUE DE CODE L’analyse statique de code consiste à étudier un programme source sans exécution du code en faisant

appel à des listes de défauts typiques ou à des métriques dont les valeurs acceptables sont définies dans le plan qualité du projet.

Cette activité doit être réalisée avant le processus de tests informatiques car elle permet souvent de mettre en évidence des erreurs de logique qui peuvent être coûteuses à corriger si elles sont découvertes tard.

Les moyens mis en œuvre: étude visuelle du programme source , étude graphique du flot de contrôle, des graphes d’appels, métrologie du logiciel. Les résultats: logique employée dans le programme, communications entre les composants, erreurs syntaxiques et structurelles, style employé.

9.3.1. EXEMPLE DE CHECK LIST POUR L’INSPECTION DE CODE Voici un exemple de liste de défauts typiques à examiner lors de l’inspection de code. Bien entendu cette

liste n’est pas limitative et doit être adaptée à chaque langage. Le plan qualité prévoit en général l’utilisation de règles de programmation qui doivent également être vérifiées.

Références aux données variables non initialisées "dangling pointers" indices de tableaux compris entre les bornes records à champs variables ou unions Calculs conversions de types underflow / overflow division par zéro précédence des opérateurs Comparaisons entre types consistants vérifier opérateurs > >= et > >= vérifier expressions booléennes & ou not attention aux mélanges Contrôle terminaison des boucles sortie des procédures et fonctions conditions initiales une itération en trop (ou en moins) toutes les possibilités d’un case testées.

9- 10 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.3.2. METRIQUES Nous abordons ici les métriques les plus connues. De nombreux efforts sont faits actuellement pour en

produire d'autres et en particulier dans le domaine des logiciels orientés objets, mais aucune n'a pour l'instant surpassé (en nombre d'utilisateurs) ces métriques aujourd'hui classiques.

Il s'agit essentiellement de corréler un certain nombre de mesures objectives calculées à partir du code produit aux facteurs de qualité visés: maintenabilité, correction, flexibilité, portabilité.

Des outils proposent la mesure effective de ces grandeurs (logiscope par exemple). Mais attention: Ces mesures fournissent des indications qui doivent toujours être corrélées au segment de

code étudié. une mesure aberrante peut être justifiée une mesure correcte peut provenir d’un code abominable!

9.3.2.1. Métrique d'Halstead (77) Il s'agit d'une métrique textuelle, elle vise à évaluer la taille d'un programme et l'effort nécessaire en

fournissant une alternative au calcul du nombre de lignes de code source. Toutefois, cette méthode utilise un calcul a posteriori et ne peut donc en aucun cas supplanter COCOMO ou la méthode des points de fonction.

La théorie établit qu’il existe des invariants pour un algorithme bien codé (c’est à dire sans redondances ou constructions inutiles) qui peuvent être utilisés pour prédire d’autres attributs d’un programme: son implémentation, sa maintenabilité.

La base des mesures est fournie par le vocabulaire utilisé. On évalue le nombre d’opérateurs et

d’opérandes. n1 = nombre d’opérateurs uniques n2 = nombre d'opérandes uniques N1 = nombre total d’apparition de ces opérateurs N2 = nombre total d’apparition de ces opérandes. Taille du vocabulaire n=n1+n2 Longueur du vocabulaire N=N1+N2 On démontre (empiriquement) que la longueur calculée du programme peut être approximée par Nc = n1 log2 n1 +n2 log2 n2 Où log2 réduit la valeur de la longueur au nombre de bits nécessaires pour exprimer chaque opérande et

opérateur de manière unique. On peut utiliser cette mesure associée au critère de concision en calculant pour chaque module Concision= 1 - (Nc- N0 ) / N0 avec N0 = longueur observée On peut également mesurer la complexité textuelle de chaque module (associée au critère de simplicité)

par la formule Complexité textuelle de mi = n1 * N2/2 * n2 Halstead propose également de calculer le volume du programme: V= Nlog2 n et approximer L, niveau du programme par L’= (1+M) /n1 . n2/N2 avec M = nombre de modules.

Validation- vérification Anne-Marie Hugues 26/09/2001 9-11

Le produit du niveau de programme par le volume est appelé le volume potentiel V*du programme; il ne dépend que de l’algorithme et Halstead estime qu’il est raisonnablement invariant lorsqu'un programme est traduit d’un langage dans un autre.

Suivant le langage utilisé, différentes implémentations du même algorithme auront différents volumes

suivant le niveau du langage utilisé. Ces différences s’expriment en fonction du niveau du langage λ calculé comme

λ = LV*, λ est vu comme une propriété intrinsèque du langage de programmation. Halstead définit d’autres formules comme par exemple: la difficulté du programme notée D=1/L l’effort noté E= V/L De nombreuses études ont prouvé que la théorie est relativement inadéquate mais que quelques mesures

peuvent s’avérer utiles. En particulier même si le nombre d’opérandes et de d’opérateurs est fortement corrélé au nombre de lignes, l’étude de ceux-ci fournit une granularité plus fine que celle des lignes de code source. Il introduit également la notion de niveau de langage et la lie à l’effort de programmation.

9.3.2.2. Mesurer du logiciel selon Mac Cabe (76) Mac Cabe propose quant à lui d’étudier le logiciel en analysant le graphe de contrôle du programme et

calcule la complexité structurelle ou nombre cyclomatique de ce graphe Soit n = Nombre de nœuds (blocs d’instructions séquentielles) e = Nombre d’arcs (branches suivies par le programme) v = nombre cyclomatique Le nombre cyclomatique donne une évaluation du nombre des chemins indépendants dans le graphe et donc une indication sur le nombre de tests nécessaires (nombre de décisions +1 pour un programme bien structuré). L’interprétation du nombre cyclomatique n’a de sens que pour un graphe fortement connexe. On rajoute

donc le cas échéant p arcs pour rendre le graphe connexe Calcul du nombre cyclomatique: Cas n° 1: 1 point d’entrée; 1 point de sortie v= e-n +2 Cas n° 2 i points d’entrée; s points de sortie v = e - n + i + s Exemple: if C1 then while (C2) loop X1; end loop; else X2; X3;

9- 12 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

C1

C2 X2

X1 X3 n=5,e=6

V=3 (nombre de décisions =2) NB: i=1 et s=1 Conclusions Le nombre cyclomatique calculé au niveau de chaque procédure permet de mettre en évidence les parties

trop complexes. Des études expérimentales ([GRE 76], [CUR 79] indiquent différentes relations entre cette métrique et le nombre d’erreurs.

Dans la pratique il semble que la limite supérieure du nombre cyclomatique soit de 30 environ. Au delà la procédure est difficile à tester [PRE 87]. La valeur maximum du nombre cyclomatique peut être définie comme un critère de qualité dans le plan qualité.

Il est bon toutefois de noter les limites de cette métrique qui ne prend en compte que le graphe de contrôle du programme à l'exclusion de toute évaluation concernant les données.

On citera par exemple la construction switch en C (ou case en Pascal Ada ) dont le nombre cyclomatique peut s'avérer catastrophique (liée à la taille du switch)et dont la compréhension est pourtant fort simple.

9.3.2.3. Métrique de Henry et Kafura (81) Cette métrique prend en compte les liaisons inter modules, elle propose de calculer pour chaque module sa

complexité, à partir de sa taille, son fan in et son fan out. fan in = nombre de modules en entrée du module + nombre de données globales en entrée fan out = nombre de modules en sortie du module + nombre de données globales en sortie. La métrique calcule ensuite le produit

longueur*(fan in*fan out)2 Cette métrique a été largement testée sur Unix. Contrairement à la métrique proposée par Mac cabe, le module est analysé en fonction de son contexte.

Une métrique élevée indiquera une certaine complexité d'intégration du module et une compréhensibilité douteuse. Cette métrique s’adapte bien dans le contexte orienté objets.

9.3.2.4 Encombrement d’une classe Cette métrique mesure le couplage entre deux classes Définition : soit E1 l’ensemble des classes référencées directement par la classe C C hérite de D C a un attribut de la classe D C a une opération avec un argument d ’entrée de la classe D C a une variable de D une méthode de C envoie un message retournant un argument de classe D

Validation- vérification Anne-Marie Hugues 26/09/2001 9-13

une méthode de C contient une variable locale de classe D C fournit D comme paramètre effectif à une classe paramétrée C a une classe amie D (C++)

Soit E2 : Ensemble des classes référencées indirectement par C qui est la fermeture transitive de l ’ensemble précédent.

On définit : Encombrement direct =cardinal de l ’ensemble E1 Encombrement indirect = cardinal de l ’ensemble E2 Encombrement total = cardinal de E1 + E2

F2F1 F3

E1

E2

L ’ensemble des classes référencées directement par la classe C est utilisé également lors des tests

d ’intégration de classes pour étudier l ’ordre d ’intégration.

9.3.2.4. Conclusion Il existe de nombreuses autres métriques permettant de mesurer le critère de simplicité; on peut par

exemple compter le nombre de conditions par négation ou compliquées (plus de 3 opérateurs dans une condition booléenne); on peut aussi mesurer par exemple le nombre de niveaux d’imbrications (Ada, Pascal) ou d'ancêtres d'une classe (C++..).

En conclusion, et malgré toutes les recherches en cours, on peut dire qu'il n'existe guère de métriques

radicalement plus pertinentes que les cinq métriques de base: taille, coût, effort, durée et qualité (en nombre de fautes détectées). Toutefois les 3 métriques décrites ici peuvent être utilisées comme indicateurs de certains facteurs de qualité.

9.4. L'ACTIVITE DE TESTS Quelle que soit l'efficacité des méthodes statiques, elle ne peuvent supplanter l'activité de tests. Les tests

permettent de vérifier de manière dynamique que le produit réalisé est conforme aux intentions. L’activité de tests est aussi vieille que le développement mais elle est encore trop souvent empirique. Elle est pourtant le dernier rempart contre les erreurs résiduelles.

9- 14 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.4.1. ASPECTS PSYCHOLOGIQUES: INFLUENCE SUR LA GESTION DE PROJET L’activité de tests doit être considérée comme un processus destructif, un moyen de mettre en évidence

des erreurs ; si on n’y aboutit pas, c’est un échec. Une mauvaise approche consiste à vouloir démontrer que le programme “marche”, car les tests sont alors choisis en conséquence.

Ainsi il est plus facile de trouver les erreurs des autres que les siennes propres, il est donc préférable que les équipes de développement et d'intégration/qualification soient différentes.

Les budgets de qualification et de développement doivent également être séparés.

9.4.2. FACTEURS DE TESTABILITE La testabilité d’un document est la facilité avec laquelle les tests peuvent être développés à partir de ce

document (faisabilité, coût, critère de décision de succès ou d’échec). Elle se prépare tout au long du cycle de vie.

En particulier en phase de spécifications fonctionnelles chaque élément requis doit être compréhensible, spécifique, quantifié.

En phase de conception globale et détaillée, les facteurs de bonne testabilité sont: - traçabilité, - architecture simple et modulaire, - abstraction à travers les interfaces - politique claire de traitement des erreurs.

De même les facteurs de mauvaise testabilité sont: - très fortes contraintes d’espace mémoire et d’efficacité, - absence de critères de classement des contraintes et attributs, - intégration forte des traitements, - longue chaîne de traitement, - architecture construite par addition de fonctions.

9.4.3. LIMITES THEORIQUES Prouver que deux programmes quelconques calculent la même fonction est indécidable. C'est à dire qu'elle

ne peut être prouvée dans le cas général. Il n’existe donc pas de test général prouvant qu’un programme n’a pas d’erreur. Il n’existe pas de test montrant qu’un chemin du flux de contrôle ne contient pas d’erreur. Le fait qu’une donnée d’entrée arbitraire excite une instruction particulière, une branche particulière, un chemin de contrôle particulier; ou qu’une donnée particulière excite chaque instruction, chaque branche, chaque chemin est indécidable.

Tout ce qui suit consiste donc à trouver des heuristiques permettant de s’approcher de la notion de 0-défaut en prouvant au cas par cas qu'un programme implémente ses spécifications

9.4.4. ORGANISATION DE L’ACTIVITE DE TESTS La construction des tests doit permettre de révéler si le logiciel contient des erreurs avec un investissement

optimum c’est à dire: - une taille minimum, - une probabilité maximum de détection d’erreur, - une possibilité d’incrémentalité.

Les jeux de tests doivent être construits comme des produits, ce sont des sous ensembles des entrées judicieusement choisis.

L'organisation prend en compte 4 étapes - sélection des jeux de tests

Validation- vérification Anne-Marie Hugues 26/09/2001 9-15

- soumission des jeux de tests - dépouillement des résultats - évaluation de la qualité des tests, décision d'arrêter les tests.

Ces tâches constituent un important problème de gestion de projet et doivent être planifiées très tôt (difficile d'accroître les ressources en fin de développement!).

Les environnements de tests permettent la mise en œuvre de jeux de tests et la réalisation de données et contextes. Ils définissent les critères de conclusion et permettent d’automatiser le diagnostic. Il assurent la diffusion des résultats.

9.4.5. SCHEMA GENERAL D’UN PLAN DE TESTS La planification vise à rationaliser l’activité de tests. On décompose les erreurs en différentes classes

(propres à une étape, communication entre deux étapes, erreurs de calcul, erreur de contrôle). . On distingue différents types de tests intervenants à différents moments du cycle de vie:

- tests unitaires (pendant le développement), - tests d’intégration (pendant le développement), - tests de validation (chez le fournisseur par l’équipe de qualification), - tests de validation (chez le client), - tests de suivi d’exploitation.

Les trois derniers tests se décomposent en tests de fonctionnalités, et tests de performances. Toutes ces étapes ne sont pas nécessairement présentes et dépendent de la criticité du logiciel considéré. Le schéma général d’un plan de tests doit être abordé dès la phase de spécifications fonctionnelles lors de

la rédaction du plan projet et du plan qualité. Il doit préciser les points suivants: - Définir les préconditions pour les tests, - Définir les étapes de tests et critères de satisfaction associées, - Chronologie et durée des étapes de tests, - Pour chaque étape chronologie et moyens de mise en œuvre des différents jeux de tests, - Modes d’intégration, - Equipes concernées et responsabilités, - Procédures de suivi pour l’évaluation du degré de réalisation des tests, - Procédure de collecte de données statistiques, - Actions à prendre en cas d’erreurs, - Procédures de mise au point, - Tests de non régression, - Procédure de report des corrections, - Normes, - Outils et méthodes recommandés, - Temps de calcul et configuration matérielle, - Bibliothèques de tests.

Les critères de satisfaction doivent être définis: - épuisement des ressources, - aucune erreur révélée, - taux de couverture atteint, (cf plus loin tests strucurels) - durée , - nombre d’erreurs découvertes (avec catégories), - étude de courbe nombre d’erreurs en fonction de la durée.

Nous étudions dans les paragraphes suivants différentes techniques de tests unitaires ainsi que des méthodes de preuves. Nous présentons différents modes d’intégration.

9- 16 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.5. CONSTRUCTION DE TESTS UNITAIRES OU TESTS DE MODULES Les tests unitaires peuvent se faire selon différentes stratégies. Elle diffère par le processus de sélection

des jeux de tests On peut examiner les spécifications et évaluer la réaction du logiciel à certaines entrées, il s’agit du test dit de boite noire. On peut examiner la structure du programme et vérifier que toute la structure est parcourue lors du passage des jeux de tests. On mesure alors le taux de couverture des tests. On peut compléter ces méthodes par du test aléatoire sur des jeux de données tirés au hasard.

9.5.1. TESTS FONCTIONNELS OU TEST DE BOITES NOIRES (BLACK BOX TESTING)

Il s’agit d'évaluer la réaction du logiciel à certaines entrées sans examiner l'intérieur des différents modules. On parle aussi de tests fonctionnels ou de tests de fonctionnalité destinés à vérifier les contraintes liées aux spécifications.

9.5.1.1. Partition en classes d'équivalence Le problème consiste à définir des entrées représentatives en limitant le nombre de tests. On partitionne

le domaine d'entrée (éventuellement infini) en un nombre fini de classes d'équivalence. Chaque représentant d'une classe a la même probabilité de mettre en évidence une erreur . Il convient de prendre en compte les données valides et non valides.

Exemples: 1..99 donne 3 classe: [1, 99], > 99 , < 1 (émetteur, destinataire, réseau ) donne 4 classes dont 3 valides. On notera qu'une donnée valide peut représenter plusieurs classes d'équivalence mais ce n'est pas le cas

pour une donnée invalide.

9.5.1.2. Analyse aux bornes du domaine : Boundary domain analysis Afin de vérifier les critères liés aux erreurs et aux spécifications, on est amené à faire une analyse précise

aux bornes des classes d'équivalence des valeurs d'entrée. Il faut considérer certaines combinaisons des entrées en fonction des sorties à obtenir. On sélectionne un représentant d'une valeur médiane et plusieurs valeurs aux bornes (avec des

précisions différentes pour les applications de calcul numérique). Cette activité requiert un travail créatif et de spécialisation. Des méthodes sont disponibles pour

sélectionner les classes d'équivalence significatives. Nous décrivons la plus utilisée dans le paragraphe suivant.

Validation- vérification Anne-Marie Hugues 26/09/2001 9-17

9.5.1.3. Graphe cause à effet: Cause effect graphing Cette méthode permet de sélectionner des combinaisons de valeurs d'entrée de manière systématique, en construisant un graphe liant causes et effets avec des opérateurs logiques (à ne pas confondre avec un quelconque graphe représentant le flot de contrôle du programme). La sémantique du programme est représentée par un graphe ou une table de décisions dont chaque colonne définit un test..

On définit un langage graphique semi formel

identité a b négation a b a ou b d c a et b d c

Ce formalisme permet d'étudier les combinaisons de données d'entrées. On travaille toujours sur un élément de taille réduite. On traduit une cause par une condition d'entrée ou une classe d'équivalence. On traduit un effet par une condition de sortie. On numérote chaque cause et chaque effet. L'analyse aux limites du domaine se fait à part

9- 18 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

Exemple d'après Myers Commande DISPLAY pour examiner les zones mémoire dans un débuggeur. DISPLAY [HEXLOC1 HEXLOC2] 0 (défaut) END nombre d’octets 1 (défaut) HEXLOC est une adresse hexadécimale de 1 à 6 chiffres comprise entre les adresses valides. On définit les classes d ‘équivalence des entrées (causes) On définit le graphe, on en déduit les effets et les causes qui les ont provoquées

CAUSES 1 : le premier opérande est présent 2 HEXLOC1contient uniquement des chiffres hexadécimaux 3 HEXLOC1contient 1 à 6 caractères 4 HEXLOC1 est compris dans les adresses valides 5 le deuxième opérande est END 6 le deuxième opérande est HEXLOC2 7 le deuxième opérande est nombre d’octets 8 le deuxième opérande est omis 9 HEXLOC2 contient uniquement des chiffres hexadécimaux 10 HEXLOC2 contient 1 à 6 caractères 11 HEXLOC2 est plus grand ou égal à HEXLOC1 12 HEXLOC2 est compris dans les adresses valides 13 nombre d’octets ne contient que des chiffres hexadécimaux 14 nombre d’octets contient 1 à 6 caractères 15 HEXLOC1+ nombre d’octets <= taille mémoire +1 16 nombre d’octets >=1 17 la zone à afficher est suffisamment grande pour nécessiter plusieurs lignes 18 La zone à afficher ne démarre pas sur frontière de mot EFFETS 91 : Message M1 « commande invalide » 92 Message M2 « déplacement au delà de la mémoire » 93 Message M3 « déplacement nul ou négatif » 94 Le contenu de la mémoire est affiché sur une ligne 95 Le contenu de la mémoire est affiché sur plusieurs lignes 96 Le premier octet de la zone affichée tombe sur frontière de mots 97 Le premier octet de la zone affichée ne tombe pas sur frontière de mots

Validation- vérification Anne-Marie Hugues 26/09/2001 9-19

On construit ensuite une table de décision

Chaque colonne de la table représente un test qui doit être effectué. On pose un effet à 1 et on cherche les causes (combinaisons des entrées) produisant cet effet avec les

règles suivantes: - pour vérifier un effet produit par un et sur plusieurs entrées on met une seule entrée à 0 à la fois, - pour vérifier un effet produit par un ou sur plusieurs entrées on met une seule entrée à 1 à la fois

Le programme est testé lorsque tous les effets ont été produits.

9.5.1.4. Conclusion Les tests fonctionnels permettent de tester le produit en le confrontant directement à ses spécifications, les

tests fonctionnels peuvent être définis très tôt ( dès la phase de spécification dans le cycle en V). Leur construction peut également s'appuyer sur l'étude des diagrammes de flots de données.

Alors que les tests fonctionnels sont très populaires, il n'existe pas aujourd'hui d'outil d'assistance largement répandu; les efforts dans ce domaine portent plutôt sur des outils d'assitance au test structurel comme on le verra dans le paragraphe suivant.

Les seules méthodes systématiques pour la construction des tests fonctionnels sont celles issues des spécifications formelles; on peut alors utiliser les tests fonctionnels pour tester des spécifications intermédiaires.

Il est à noter que lors du test fonctionnel on teste ce que le programme est censé faire et non pas ce qu'il fait vraiment comme dans le test structurel.

9- 20 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.5.2. TESTS STRUCTURELS OU DE BOITE BLANCHE (WHITE/ GLASS BOX TESTING)

9.5.2.1. Principes du test structurel Il ne s'agit plus ici de valider la conformité aux spécifications mais d'examiner la structure de chaque

module en examinant son graphe de flot de contôle et/ou son graphe de flot de données. Le programme est décomposé en portions de code; on l'exécute avec des jeux d'essais préétablis, on marque ensuite les portions de code testées grâce à ces jeux de données.

La stratégie est la même que pour les tests fonctionnels mais au lieu de marquer les effets testés on marque les portions de code testées, ce marquage définit la couverture des tests.

L’approche “boîte blanche” est basée sur l’analyse de chemins existants dans le programme. Idéalement on voudrait pouvoir tester tous les chemins mais ils peuvent être en nombre très grand voire infini; le test exhaustif n’est donc pas possible comme on le voit sur l’exemple suivant.

B

A

<21

On voit sur cet exemple que sur un programme dont le graphe de contrôle comporte une quinzaine d'arcs

(de complexité 6 au sens de Mac Cabe) il existe un nombre importants de chemin différents menant du point A au point B

51+52+....520= 1014 chemins différents Si un test dure 5mn il faudrait un milliard d'années pour les passer tous!!! On cherche donc des compromis; suivant les types d’erreurs que l’on veut mettre en évidence, on pourra

être conduit à utiliser différents critères pour définir les tests structurels on s’intéresse alors :

Validation- vérification Anne-Marie Hugues 26/09/2001 9-21

- aux composants du programme, (variables, instructions) - aux flots de contrôle - aux flots de données - aux états (erreurs de logique)

Exemples de types d’erreurs détectées - Absence de chemin: on doit effectuer un traitement spécial sur deux variables

en cas d’égalité mais ce n’est pas fait dans le programme - Sélection de chemin la condition d’un if doit être < et c’est programmé <= - Calcul on doit écrire a+b et on a programmé a-c

9.5.2.2. Critères relatifs aux composants La stratégie de tests est guidée par les objets: instructions ou données. On peut chercher à construire des jeux de tests couvrant toutes les instructions :

- toute instruction est exécutée au moins une fois ou bien couvrant toutes les données

- chaque donnée est utilisée au moins une fois.

Ces tests sont largement insuffisants comme on le voit sur les exemples ci-dessous Exemples

if x > 0 then S endif On passe sur cette instruction avec x>0 mais il faudrait également tester avec x<0 a:=b+c.....a:=b- c On utilise a, b et c au moins une fois pour b+c mais il faudrait également l'utiliser pour b - c Ces tests peuvent être intéressants pour montrer qu'on ne peut jamais exécuter une instruction

9- 22 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.5.2.3. Analyse du flot de contrôle Définition: Graphe de flot de contrôle d’un programme Les remarques précédentes nous conduisent à analyser plus précisément le graphe de contrôle du

programme. Exemple Soit le programme suivant:

for I := 1 .. 100 loop if A>B then X:= 3 T:= 25; else Y:=4; endif; Z:=5 end loop; Son flot de contrôle est le graphe suivant:

entrée i:=1 I<=100 sortie A>B X:=3 Y:=4 T:=25 Z:=5 I:=I+1

Chaque noeud représente soit l'évaluation d'une expression conditionnelle comportant seulement un point

d'entrée, soit une suite d'instructions indivisible n'ayant qu'un point d'entrée et un point de sortie. On étudie différentes façons de couvrir ce graphe par les jeux de tests.

Validation- vérification Anne-Marie Hugues 26/09/2001 9-23

Couverture des branches, Branch coverage On peut s'intéresser à la notion de "branch coverage" ou "decision coverage", c'est à dire que l'on

cherche à construire des tests permettant de faire en sorte que toute branche soit exécutée au moins une fois. Cette mesure bien que plus satisfaisante que le test couvrant toutes les instructions est insuffisante comme

le prouvent les exemples ci-dessous Exemples

if A>0 then ....endif if B>0 then ....endif

Si on prend les données (A=1 et B=1) (A=-1, B=-1) on passe bien sur toutes les branches mais on néglige la combinaison (A=1, B=-1) if A>0 and B>0 then...endif

même problème ici on teste toutes les branches en mettant A ou B à 0. Il faudrait tester en mettant A et B à 0

Sur le graphe de contrôle suivant, on voit que le test de chemin est impossible (infinité de chemins) et

que le test de branches n'est pas satisfaisant car on obtient la couverture avec un seul chemin (1, 2, 3, 2, 4) Rien n'impose dans le test de branches de passer plusieurs fois dans une boucle.

1 read (a,n) b:=a; 2 n>1 n<=1 3 4 b:=b * a return (b) n:=n-1

Il faut donc trouver des méthodes intermédiaires Couverture de tous les i-chemins On définit une nouvelle notion: la portion linéaire de code suivie d'un saut (PLCS) ou linear code

sequence and jump. On nomme ainsi toute séquence d'instructions source entre deux branchements. La couverture de tous les i-chemins implique que: Chaque PLCS doit être exécutée au moins une fois. Chaque chemin complet <n doit être exécuté au moins une fois si n est le nombre de PLCS. Ce test est plus exhaustif que celui couvrant toutes les branches comme on peut le voir sur les PLCS

associés à une boucle do ( 3 jeux de tests différents)

9- 24 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

Exemple

Read (N) For I:=1 to N do begin ..... ...... end

1 2 3

a

d

b

c

e

-1 Saut : e d c cibles (2) (3) PLCS p1 (1) -> (3) p2 (1,2,3) -> (-1) p3 (2) -> (2) p4 (1,2) -> (2) p5 (3) -> (-1) p6 (2,3) ->(-1)

Validation- vérification Anne-Marie Hugues 26/09/2001 9-25

Couverture des branches essentielles On définit une branche non essentielle comme une branche exécutée chaque fois qu'une autre branche

particulière est exécutée. Autrement dit, une branche non essentielle est un passage obligé. La couverture des branches essentielles exige que chaque branche essentielle soit exécutée au moins

une fois. L'intérêt de la méthode provient d'une diminution du nombre de tests redondants par rapport à la

couverture de tous les i-chemins, on aboutit à une meilleure définition du nombre de branches prises en compte (-40%); la sélection de tests supplémentaires est facilitée.

Exemple 1

repeat .... ..... until C1

a

c

C1?

d

C1 vrai

b C1 faux

4 branches 2 branches essentielles b, d cas 1 C1 vrai (pour exécuter c) cas 2 C1 faux au premier passage C1 vrai au deuxième passage

9- 26 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

Exemple 2

if C1 then if C2 then else endif else endif

a

c

C1C1 vrai

C2

C2 vraid

e

b

3 chemins 5 branches 3 branches essentielles c, d, e

Cas 1 C1= C2= Vrai Couverture des branches (cas 1) = 3/5 Cas 2 C1 = vrai C2 = faux Couverture de branche (cas 1 et cas 2 ) = 4/5 Cas 3 C1= faux Couverture de branche (3 cas réunis) = 1 Autres méthodes Il existe d'autres méthodes visant à réduire le nombre de tests sans pour autant perde en généralité. Nous

citerons le structured path testing qui travaille sur une réunion des chemins ne différant que par le nombre d'itérations.

Le Boundary interior path testing utilise quant à lui des critères de réunion légèrement différents: on choisit les chemins

- sans itération (boundary tests), - ayant au moins une itération ( interior tests)

On exécute au moins une fois - les chemins différents sans itération, - les chemins différents pour une première itération.

Exemple

Validation- vérification Anne-Marie Hugues 26/09/2001 9-27

while do 2 boundary if ...then ...else ....endif od 4 interior

9- 28 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.5.2.4. Analyse du flot de données L'analyse des flots de données prend en compte, pour chaque variable, ses points de définition (DEF) ses

points d'utilisation dans des instructions de calcul (C-REF) et ses points d’utilisation dans des prédicats logiques (P-REF) et leurs relations. En résumé on s’intéresse aux couples

définitions - références (dans un calcul ou une condition)

1 read (a,n) DEF a, DEF n, DEF b b:=a; C_REF a 2 P_REF n n>1 n<=1 3 4 b:=b * a return (b) C_REF b n:=n-1 DEF b DEF n C_REF n C_REF a C_REF b

Dans l'exemple ci-dessus: DEF C-REF P-REF a 1 1,3 b 1,3 3,4 n 1,3 3 (2,3) (2,4) Comme pour l'analyse basée sur les graphes de flot de contrôle, on a le choix entre différents critères. Couverture de toutes les définitions (DEF) Chaque définition est exécutée au moins une fois par un chemin qui atteint une utilisation. Exemple: 1 et 3; d'où le chemin 1,2, 3 Couverture de toutes les utilisations (C_REF et P_REF) Chaque définition est exécutée au moins une fois pour toutes les utilisations qu'elle atteint et tous les arcs

issus de ces utilisations sont couverts. Exemple variable a: 1 2 3 variable b: 3 2 3 ; 3 2 4 variable n: 1 2 3 ; 1 2 4 ; 3 2 3 ; 3 2 4 Les sous chemins nécessaires sont donc 1,2,3 1,2,4 3,2,3 3,2,4 D’où les chemins à tester 1,2,3,2,3,2,4

Validation- vérification Anne-Marie Hugues 26/09/2001 9-29

et 1,2,4 Couverture de tous les P_REF On se limite aux utilisations dans d'un prédicat (moins fort que couverture de toutes les utilisations) variable a : rien variable b : rien variable n: 1 2 3 ; 1 2 4 ; 3 2 3 ; 3 2 4 Couverture de tous les DEF_REF chemins Chaque définition est exécutée au moins une fois pour toutes les utilisations qu'elle atteint et tous les arcs

issus de ces utilisations sont couverts. De plus chaque sous chemin entre une définition et une référencequ'elle atteint doit être exécuté, on se limite aux chemins qui passent au plus 1 fois dans chaque boucle.

Dans l'exemple précédent, cette couverture n'ajoute rien aux chemins à tester.

9.5.2.5. Critères relatifs aux états Les tests sur les chemins ne permettent pas de détecter des erreurs logiques ou de calcul. Un autre

ensemble de méthodes consiste à s'intéresser aux différents états du programme; un état est constitué par l'ensemble des valeurs des variables du programme à un moment donné.

On est amené à considérer l'ensemble des décisions et l'ensemble des calculs; on aboutit à des tests des prédicats ou des tests de sous-expressions.

Tests de prédicats " predicate value oriented" "Condition coverage" On peut imposer que chaque condition composant une décision soit exécutée au moins une fois avec

chacune de ses valeurs (vrai, faux). C’est insuffisant comme le montre l’exemple ci dessous.

Exemple condition tests

écrit correct suffisants manquants a<= b a<b a<b , a>b a=b a or b a and b a=b=vrai

a=b=faux a=vrai b=faux a=faux b=vrai

"Minimal multi condition coverage"

On raffine la méthode précédente: chaque combinaison possible des conditions d'une décision est exécutée au moins une fois avec chacune de ses valeurs.

Tests orientés calculs Exemple d’erreurs de calculs et de tests adaptés

écrit correct test souhaitable a:=b/c c=0 a:=x a:=y x#y

a:=b+c a:=b-c c#0

Il s'agit de choisir les données de manière à ce que chaque sous-expression influence la valeur de

l’expression à laquelle elle appartient.

9- 30 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.5.2.6. Conclusion Hiérarchie d'inclusion entre les critères Le schéma ci-dessous donne une hiérarchie entre les différentes mesures de couverture

tout chemin tout chemin D-U tout PLCS calcul sur les valeurs tests de prédicats toute branche toute instruction toute donnée Mais beaucoup de stratégies sont incomparables et la supériorité n'est pas quantifiable.

Il existe de nombreux autres critères pouvant être pris en compte. Pour toutes les méthodes présentées, il est à noter que certains chemins sont infaisables et que l'on ne pourra donc jamais obtenir de jeux de tests fournissant une couverture de 100%

Moyennant cette légère restriction, les tests structurels permettent d'avoir l'assurance que toutes les parties d'un programme ont été essayées. Elles doivent donc faire partie de l'effort de test global.

Toutefois, elles présentes des faiblesse dues au fait qu'elles s'appuient sur le code réalisé: - les jeux de tests doivent être recalculés à chaque modification - les tests valident ce que le logiciel fait et non pas ce qu'il est censé faire, il convient donc de le

compléter par du test fonctionnel. Exemple soit le programme suivant:

if (x+y+z)/3 == x printf 'les 3 nombres sont égaux' else printf ' les 3 nombres sont différents'

On obtiendra une couverture maximum avec les jeux de tests structurels suivants: x=1,y=2,z=3, le programme répond à juste titre que les nombres sont différents

x=y=z=2, le programme répond à juste titre que les nombres sont égaux Et pourtant....

Validation- vérification Anne-Marie Hugues 26/09/2001 9-31

9.6. LES PREUVES DE PROGRAMMES La preuve constitue une alternative ou plutôt un complément aux tests de modules. Elle se pratique sur les

modules dont la criticité est suffisamment importante pour que l'on veuille assurer la correction absolue. On peut vouloir démontrer qu'une spécification est correcte, c'est à dire en cohérence avec les besoins

exprimés par l'utilisateur: par exemple qu'une certaine conjonction d'événements ne se produira jamais, que la spécification a certaines propriétés: complétude, terminaison.... On fait alors de la validation.

On peut aussi vouloir démontrer qu'un produit est correct, c'est à dire qu'il implémente ses spécifications: on fait alors de la vérification.

Nous nous intéressons particulièrement aux preuves de conception (vérification), les preuves de spécifications ayant été abordées dans le chapitre consacré aux spécifications formelles.

Une preuve est une technique mathématique On distingue deux types de preuves de programme: les preuves informelles les preuves formelles.

9.6.1. PREUVE INFORMELLE DE CONCEPTION La preuve informelle s'appuie sur la validité de certains invariants mathématiques dont on prouve qu'ils

sont vrais tout au long de l'exécution du programme. Nous abordons la technique sur un exemple.Soit le programme suivant et son graphe de

contôle.:

i=0 s=0

i>n?

s=s+tab[i]

i=i+1

oui

A B

C

D

H

E

F

G

int i,s; int tab [n]; i=0; s=0; while (i<n) { s=s+tab[k] i=i+1 }

On veut montrer que ce programme calcule dans s la somme des n termes du tableau tab. A l'entrée du graphe, au point A, on a l'assertion suivante: A: n est un entier. A la sortie , au point H on a de même H: s= tab[0] + tab[1]…………+tab[n-1] et i=n On cherche à exhiber un invariant de boucle, c'est à dire une expression mathématique valide quelle que

soit l'itération au point D du graphe. D: i<= n et s=tab[0] + tab[1]…………+tab[i-1] C'est cet invariant de boucle dont on prouve la validité pas à pas.

9- 32 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

Les preuves décrites ci-dessus sont appelées preuves informelles car elles sont déroulées sans faire appel à un formalisme strict . Elles peuvent être très utiles néanmoins, en particulier si les invariants de boucle sont élaborés en cours de développement et que la preuve informelle est déroulée en même temps que la programmation.

La difficulté réside dans la recherche des invariants de boucle.

9.6.2. PREUVES FORMELLES Dans le paragraphe précédent, nous avons introduit une démarche. Nous la mettons en œuvre plus

strictement dans ce paragraphe. Tout comme une démonstration en mathématiques, la notion de preuve formelle repose sur un système

formel composé - un langage de formules - un sous-ensemble de formules appelées les axiomes, vrais par définition - un ensemble de règles de déduction, appelées règles d'inférence. La preuve formelle ne peut être utilisée que si les spécifications ont été développées dans un langage

formel. On procède par étape en prouvant que deux étapes intermédiaires sont équivalentes. On prouve la validité de la conception par rapport aux spécifications et celle du code par rapport à la conception. Si les deux étapes sont décrites dans le même langage on parle de preuve mono langage, sinon on a un langage de départ (VDM, Z, B) et un langage d'arrivée (Pascal, C, Ada...) on parle alors de preuve bi-langages.

Nous revenons sur la preuve de conception qui démontre qu'une conception est correcte par rapport à sa spécification détaillée. En pratique ces preuves sont bi-langages. Elles utilisent une logique particulière définie par Hoare déjà introduite dans le chapitre sur les spécifications formelles.

On manipule des triplets de la forme {P} instructions {Q}

où P et Q sont des assertions, c'est à dire des prédicats décrits dans un langage de spécification et les instructions sont écrites dans un langage de programmation. L'assertion P doit être vérifiée avant l'exécution des instructions, c'est la pré-condition; l'assertion Q est vérifiée après l'exécution des instructions, c'est la post-conditon.

Exemple (dans le programme ci-dessus {i=0} i=i+1{i=1}

La logique de Hoare introduit un certain nombre d'axiomes que nous avions assumé vrais dans l'exemple

de preuve informelle développé plus haut. Elle définit des règles d'inférence que nous avons utilisées implicitement dans le paragraphe précédent.

Elle ne permet pas d'aborder le problème de terminaison1 d'un programme mais permet de décrire des preuves de correction partielles.

Nous décrivons ici les règles d'inférence correspondant aux instructions de base pouvant être trouvées dans la plupart des langages impératifs.

1 La terminaison peut être prouvée séparément et ne sera pas abordée ici, il faut savoir que ce problème est beaucoup plus ardu

que celui de la correction partielle

Validation- vérification Anne-Marie Hugues 26/09/2001 9-33

9.6.2.1. Règles d'inférence Quel que soit le langage de programmation on a toujours la règle dite de renforcement de la pré-condition

Renforcement de la pré-condition

P' => P , {P} instructions {Q} _________________________ _______________RPRE {P'} instructions {Q} Cette formule qui utilise le modus ponens se lit

- de haut en bas, "si on a prouvé P'=>P et {P} instructions {Q}, alors on a prouvé {P'} instructions {Q};

- Ou bien de bas en haut : pour prouver {P'} instructions {Q}, il faut prouver P' => P et {P} instructions {Q}

Cette règle permet de prouver une assertion P' plus forte que P et de conclure en disant que P'=> P.

Affectation: axiome de substitution Cet axiome permet de conclure sur l'assertion vraie après une affectation. On remplace dans l'assertion de

départ toutes les occurences libres de la variable à gauche du signe affectation {Q[x\exp]} x:=exp{Q}

Séquence: axiome de composition séquentiel

{P} instructions 1{R}, {R} instructions 2{Q} _________________________ ___________________________(SEQ) {P} instructions1 ; instruction2 {Q}

Cet axiome permet de se ramener à des instructions élémentaires lors du traitement d'un bloc d'instructions. La règle s'utilise alors de bas en haut.

Instruction conditionnelle: axiome de composition conditionnelle Cette règle exprime qu'il y a deux exécutions possibles en fonction de la valeur de la condition

{condition P }instruction 1 {Q} , { condition P} instruction 2{Q} _________________________ ___________________________________________________________(COND) {P} if condition then instruction 1 else instruction 2 {Q}

Instruction while: composition de boucle La règle introduit la notion d'invariant de boucle vue précédemment dan sle paragraphe sur les preuves

informelles. La règle exprime formellement la préservation de l'invariant de boucle.

{condition Invariant } instruction { Invariant} ,P=> Invariant, {condition Invariant} => {Q} _________________________ ____________________________________________________________________________(COND) {P} while condition do instruction {Q}

Comme pour la preuve informelle la difficulté réside dans la construction de l'invariant de boucle.

9- 34 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.6.2.3. Conclusion Les techniques de preuves ont été longtemps boudées par les managers sous différents prétextes: les plus

courants étant le manque de formation, la difficulté de mise en œuvre , le coût. Cependant, les ingénieurs nouvellement recrutés sont rompus aux techniques mathématiques et le premier

prétexte commence à tomber. La difficulté est toujours bien réelle concernant l'écriture des assertions d'entrée et de sortie et surtout des invariants de boucles, toutefois des outils (démonstrateurs de théorèmes) commencent à apparaître qui permettent de dérouler automatiquement une preuve et de répondre à la question : "ce programme est il correct?"2.

Le dernier critère doit être mis en perspective par rapport au coût d'une erreur dans le programme et de ses conséquences en pertes humaines (logiciels de surveillance de centrale nucleaire, logiciels de surveillance médicale, militaires, ...) ou financières (logiciels bancaires, spatiaux...)

Nous insistons sur le fait que même lorsqu'une démarche de preuve formelle n'est pas envisagée, la construction d'invariants de boucles et d'assertions intermédiaires pendant le codage permet de garantir une meilleure qualité du code. Le langage Eiffel permet d'implémenter ces assertions par l'instruction assert qui provoque une exception et un arrêt de l'exécution lorsque la condition spécifiée dans l'assertion n'est pas vérifiée.3

Ce paragraphe sur les preuves termine les techniques liées à la vérification des modules. Nous abordons dans le paragraphe suivant la phase d'intégration

9.7. LA PHASE D'INTEGRATION La phase d'intégration intervient après la vérification unitaire des modules. Le plan d’intégration est rédigé pendant la phase de conception globale (cycle de vie en V). Il prévoit

comment les modules, une fois vérifiés, sont intégrés les uns aux autres. Il définit des tests d'intégration (tests de non régression) que le produit doit subir pour pouvoir être mis en exploitation. On utilise le graphe d'appel des modules pour aborder l'intégration de deux façons: de manière incrémentale ou de manière globale (big bang).

9.7.1. INTEGRATION GLOBALE VERSUS INTEGRATION INCREMENTALE En intégration globale, tous les modules vérifiés sont intégrés en même temps. En mode incrémental,

chaque intégration partielle est le test d'un nouveau module avec d'autres déjà intégrés et testés. Du point de vue de l’assurance qualité et du coût, l’intégration incrémentale est de loin supérieure à

l’intégration globale. En particulier le travail de développement est moindre, la détection des erreurs d’interfaces est plus précoce, leur localisation est plus aisée; les tests d'intégration sont menés de manière plus approfondie.

On peut toutefois noter que sur le plan de l’organisation du travail l’intégration globale est supérieure à l’intégration incrémentale puisqu’elle favorise la parallélisation des tests unitaires de modules. Rien n’empêche toutefois la parallélisation des tests unitaires en mode d’intégration incrémentale.

9.7.2. INTEGRATION ASCENDANTE VERSUS INTEGRATION DESCENDANTE L'intégration incrémentale peut se faire selon deux stratégies: l'intégration ascendante ou l'intégration

descendante ; elles nécessitent toutes deux la construction d'outils de simulation: des muets (stubs) ou des lanceurs de tests.(drivers )

2Il est toutefois opportun de vérifier que cet outil lui même est correct! 3contrairement à la même instruction en C++ qui est une instruction de debug...

Validation- vérification Anne-Marie Hugues 26/09/2001 9-35

On se réfère au graphe d'appel des modules décrit dans le chapitre sur la conception. . La stratégie d’intégration descendante prévoit d’intégrer le module racine en premier, un module est ensuite sélectionné pour l’intégration si tous ses ancêtres ont déjà été intégrés.

A contrario, la stratégie d’intégration ascendante prévoit l’intégration des modules feuilles en premier; un module est sélectionné pour l’intégration si ses descendants ont tous été testés. Il existe des stratégies mixtes mélangeant les deux approches.

L’intégration ascendante présente l’avantage d’éviter la construction de muets ou stubs (simulateurs de modules feuilles non encore intégrés4). La répartition du travail est plus aisée, les erreurs dans les parties critiques sont localisées plus tôt, le test de chemins particuliers est facilité. Toutefois on peut regretter que le produit lui même n’apparaisse que fort tard, en particulier les erreurs d’interface ne sont découvertes que très tardivement.

Dans l’intégration descendante, le programme apparaît tôt et les erreurs d’interfaces sont découvertes de manière plus précoce. Un des gros désavantages provient de la nécessité de construire des stubs ce qui ralentit le processus et provoque une montée en charge lente. On éprouve de la difficulté à tester des chemins particuliers et on regrette l’absence des modules d’entées/sorties. La représentation des jeux de tests est plus facile une fois les entrées-sorties insérées.

L’approche mixte ou approche sandwich peut être une alternative tirant le meilleur parti des deux stratégies.

9.7.3. Outils de tests d’intégration Le passage des tests fonctionnels peut s'avérer long et coûteux en particulier lorsque le produit possède

une interface nécessitant la présence d’un utilisateur pour tester l’ensemble des scénarios. Il existe des outils d’aide au test fonctionnel qui permettent de capturer, contrôler et rejouer automatiquement les interactions des utilisateurs permettant d'identifier les anomalies. On peut ainsi s’assurer que les processus métier, qui font intervenir des applications et des bases de données multiples, fonctionnent parfaitement dès la première fois et qu'ils demeurent fiables lors des passages de tests de non régression en cas d ‘évolution du logiciel en phase de maintenance.

(Winrunner/Mercury http://www.mercuryinteractive.fr/ ; Rational Suite, Rational Robot , Rational Visual Test http://www.rational.com/products/).

9.8. TESTS DE QUALIFICATION Lorsque le produit a passé la phase de validation, il doit être qualifié, c’est à dire évalué dans le cadre

d’une utilisation sur site en vrai grandeur, cette phase s’appelle également Béta test. Diverses techniques s’appliquent ici pour vérifier essentiellement les contraintes non fonctionnelles

spécifiées dans le cahier des charges (performances, disponibilité…)

9.8.1. TESTS ALEATOIRES Les tests aléatoires consistent à sélectionner les jeux de test par tirage aléatoire selon une loi de probabilité

uniforme, ou bien similaire à la distribution des données d'entrée présumées (on parle alors de test statistique).

La méthode de test aléatoire uniforme donne des résultats très variables selon les logiciels testés. La méthode de test statistique permet d'émettre des conjectures sur la fiabilité du futur logiciel. Il peut

permettre en particulier de décider l'arrêt du test lorsque le degré de fiabilité (temps moyen entre deux pannes) est jugé satisfaisant.

4 Ces programmes sont lourds à écrire car les modules feuilles en général contiennent beaucoup d'algorithmique.

9- 36 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification

9.8.2. OUTILS DE TESTS Des outils permettent d’évaluer la résistance à la charge et les performances. Ceci est particulièrement

utile en cas de développement de site web. Rational SiteLoad http://www.rational.com/products. Loadrunner/Mercury http://www.mercuryinteractive.fr/ ;

9.9. COMPLEMENTS

9.9.1. L'APPROCHE CLEANROOM Cette méthode de validation décrite en 90, 92, 94 rassemble différentes techniques vues précédemment à

savoir - modèle d'intégration incrémental - techniques de spécification formelles - inspection de code: en particulier, un module n'est pas compilé avant d'avoir été inspecté - preuves informelles et formelles lorsque les participants en ressentent le besoin - tests (y compris tests statistiques qui sont utilisés pendant la phase d'intégration)

Des résultats impressionnants sur des petits exemples ainsi que sur des gros ont été obtenus.[Linger 1994]

9.9.2. TESTER DES OBJETS Une des raisons mises en avant pour utiliser des objets vient du fait que la réutilisation doit éviter la phase

de tests. Un adage affirme que lorsqu'une classe a été testée et archivée elle n'a pas besoin de l'être lorsqu'elle est réutilisée, de même lorsqu'une sous classe hérite des méthodes d'une classe mère, ces méthodes n'ont pas besoin d'être retestées.

Ceci n'est que partiellement vrai. En effet une classe est par essence non exécutable, seules des instances de la classe peuvent être testées, la classe elle-même peut seulement être inspectée.

Le test fonctionnel de module en approche structurée consiste à fournir des entrées au module et à examiner ses sorties en les comparant à une valeur attendue.

Lors du test d'un objet, on va tester des méthodes qui vraisemblablement plutôt que de retourner une valeur vont modifier une variable d'état de l'objet. Pour pouvoir vérifier la correction de l'objet, il faudra envoyer de nouveaux messages à l'objet.

Le plan de tests doit alors prévoir que la valeur de chaque variable d'état est accessible lors de la phase de tests.

En ce qui concerne les méthodes héritées, elles doivent être retestées dans le contexte d'héritage.

9.9.3. TESTER DU LOGICIEL DISTRIBUE Le logiciel distribué est généralement intégré sur un environnement monoprocesseur puis qualifié dans un

environnement distribué. Les techniques de tests ordinaires sont alors inefficaces car la reproductibilité est plus difficile à obtenir. Ajouter des instructions de debuggage peut alourdir un des processeurs et altérer le comportement global du système. Un débugger distribué peut être nécessaire et l'utilisation d'un journal indispensable pour reconstituer l'environnement de test.

9.9.4. TESTER DU LOGICIEL TEMPS REEL

Validation- vérification Anne-Marie Hugues 26/09/2001 9-37

Les logiciels temps réel sont souvent des logiciels très critiques dont la robustesse doit être garantie. Ils sont souvent très complexes et induisent des problèmes de parallélisme, synchronisation... ils relèvent donc pour la plupart de la catégorie logiciels distribués vus plus haut.

En outre les tests fonctionnels sont souvent difficiles à effectuer en particulier dans les conditions aux limites (arrêt cardiaque, fuite radio-active..). Ces conditions doivent donc être simulées.

Enfin les interactions entre les différents modules peuvent être très subtiles et de petits changements peuvent avoir des conséquences désastreuses, en particulier une erreur cumulative peut se révéler seulement après des centaines d'heures d'utilisation alors que les tests n'avaient pas duré aussi longtemps et laissaient penser que le produit était correct.

Les techniques les plus utilisées sont les analyses de structures des modules (qui peuvent aider à détecter une situation de blocage), les preuves de programme (en Angleterre le gouvernement rend obligatoire cette étape pour les logiciels critiques), le test statistique, la simulation.

9.9. BIBLIOGRAPHIE J. Myers The art of Software testing Wiley Interscience M.A Ould, C. Unwin Testing in Software Development Cambridge University Press 1988 JP Cavano and JA Mc Call A Framework for the measurement of software quality Proc software quality Insurance workshop pp133-139 1978 TJ Mc Cabe A complexity measure IEEE Trans S.E SE 2:308-320 1976

Hung Quoc Nguyen Testing Applications on the Web: John Wiley 2000

Cem Kaner, Hung Quoc Nguyen, Jack Falk Testing Computer Software, 2nd Edition, John Wiley, 1999 Ron Paton

Software testing, Sams (2000)

9- 38 Copyright Anne-Marie Hugues 26/09/2001 Validation-vérification