Table des matières
Techniques de déboguage
La gestion des erreurs joue un rôle important dans le développement de logiciels. L’effort à fournir, en ressources humaines et financières, pour débarrasser un logiciel des erreurs qu’il contient peut être colossal. En général, plus une erreur fait du chemin dans le processus de développement, plus le prix à payer pour la corriger est élevé. Cela veut dire qu’il faut détecter et corriger une erreur le plus rapidement possible et ne pas la laisser se noyer dans la complexité grandissante du logiciel.
Ce document commence par dresser les types d’erreurs qui existent en programmation. Ensuite, il présente des techniques et conseils pour éviter de commettre des erreurs. Enfin, il expose des techniques pour corriger les erreurs présentes dans un logiciel.
Types d'erreurs de programmation
Il existe plusieurs catégories d’erreurs en programmation :
- Les erreurs lexico-syntaxiques : elles se produisent lorsque le programmeur ne respecte pas les règles lexicales et syntaxiques du langage.
- Les erreurs de logique : ce sont des erreurs qui changent le sens du programme.
- Les erreurs d’exécution : ce sont des erreurs qui font planter le programme ou le terminent le façon impromptue. Elles peuvent être causées par le programme lui même du à des erreurs commises par le programmeur ou par l’environnement d’exécution.
- Les situations d’exception : ce ne sont pas des erreurs proprement dites mais des situations qui peuvent se produire et empêcher le programme de fonctionner normalement. Elles sont généralement dues au comportement de l’utilisateur ou à l’environnement externe.
Les erreurs lexico-syntaxiques
Ces erreurs se produisent lorsqu’on ne respecte pas une règle lexicale ou syntaxique du langage comme, par exemple, écrire mal un mot réservé, oublier une accolade ouvrante ou fermante 1), imbriquer mal des accolades ou utiliser mal une structure de contrôle.
While (i>10) //le W doit être en minuscule {...}
int i; for (i=0 ;i<10 ;i++) ... } //où est l’accolade ouvrante?
int i; if (i>=0) { ... else //ce else doit être après }. }
Tests logiciels
C’est bien de développer des logiciels, encore faut-il qu’ils soient de qualité. La qualité d’un logiciel prend un sens différent pour chaque type d’intervenant dans le cycle de vie du logiciel. Mais de manière générale, on peut dire que la qualité est l’aptitude à satisfaire des besoins, exprimés de façon implicite ou explicite. La qualité ne se limite donc pas à l’absence d’erreurs.
Normes et standards
L’organisation internationale des standards (ISO – International Standard Organization) élabore des normes et standards dans différents domaines. L’élaboration de standards a comme objectifs :
- De faire profiter de l’expertise existante;
- D’éviter de réinventer la roue;
- D’offrir les meilleures pratiques (ou façons de faire);
- D’améliorer la visibilité des produits et services;
- De faciliter la communication du savoir et du savoir-faire;
- D’économiser temps et argent.
Les standards internationaux sont élaborés par des experts du domaine reconnus et désignés, organisés en groupes de travail, puis approuvés par des organismes internationaux tels que ISO, IEEE (Institute of Electrical and Electronics Engineers), AFNOR (Agence Française de NORmalisation), etc. Ils sont revus et améliorés périodiquement.
Les guides standards IEEE sont numérotés selon une nomenclature spécifique :
IEEE std numéro. année
En adhérant à des standards et en suivant des normes, les entreprises acquièrent des gages en ce qui a trait :
- au respect des délais de réalisation et des coûts,
- à la pertinence des développements effectués par rapport aux objectifs fixés.
- à l’intégration de la qualité dans leur fonctionnement.
- à la mise en oeuvre de méthodes de travail adaptées.
Pour obtenir la certification, l’entreprise est obligée de définir précisément les méthodes de travail et les procédures de validation.
L’ISO a désigné l’IEEE pour élaborer des normes et standards relatifs aux technologies de l’information. Dans ce domaine, trois normes sont particulièrement intéressantes :
- ISO 9000 qui est une norme qualité relative à l'organisation du travail ;
- ISO 9126 et ISO 12207 qui sont des normes qualités spécifiques au logiciel.
Le but est de déterminer une façon de faire et un langage uniformes dans le développement des logiciels, et de proposer des guides pour effectuer et documenter de manière quasi-complète les tâches inhérentes.
La qualité concerne trois aspects de l'entreprise :
- Le système qualité qui traite de l'ensemble de l'organisation, des responsabilités, des procédures, des processus et des moyens nécessaires pour mettre en oeuvre le management qualité (norme 9000 );
- Les processus de réalisation qui spécifient les moyens de réalisation du produit (norme 12207) ;
- Le produit qui doit répondre aux besoins des utilisateurs (norme 9126).
Liste de standards utiles
- ISO 9000 : organisation du travail.
- ISO 9126 : satisfaction des besoins des utilisateurs.
- ISO 12207 : moyens de réalisation du produit.
- IEEE std 829 : documentation des tests.
Conduire des tests pour évaluer la qualité d’une application doit suivre des règles et méthodes standards. Les sections suivantes décrivent brièvement les différents tests qui existent et étudient en détails les tests que doit mettre en oeuvre le programmeur.
Déroulement des tests
Phases de test
Les tests que subit une application pendant son cycle de développement se réalisent en plusieurs phases :
- Test unitaire : vise à vérifier la conformité des unités (composants) aux exigences.
- Test d’intégration : vise à s’assurer que les modules de l’application communiquent et interagissent de manière correcte, stable et cohérente.
- Test système : vise à s’assurer que l’application sera acceptée par ses futurs utilisateurs.
- Test d’intégration système : vise à s’assurer que l’application va inter-opérer avec les autres systèmes et que son fonctionnement ne nuira pas aux autres systèmes en place dans l’environnement d’exploitation, et vice versa. Ce test n’est nécessaire que si l’application est appelée à fonctionner avec d’autres systèmes logiciels.
- Test de recette (ou de réception) : vise à s’assurer de la conformité de l’application avec ses spécifications et donner confiance en son fonctionnement correct avant sa livraison officielle aux utilisateurs. Il se divise en test de recette utilisateur, qui concerne les utilisateurs finaux, et en test d’exploitation, qui concerne l’application.
Lorsque l’application subit des modifications (extensions, améliorations, mises à jour, etc), il convient d’effectuer des tests de régression pour s’assurer que ces modifications ne nuisent pas au fonctionnement de l’application. Le test de régression n’est pas un phase de test, mais plutôt un test qui s’applique à toutes les autres phases, en particulier, les tests système et de recette.
Arrêt de tests
Les coûts impliqués par les activités de test (25 à 30% du coût total du développement) et l’impossibilité de réaliser des tests exhaustifs font de la décision d’arrêter les tests une décision très important. Souvent, la décision d’arrêter est prise indépendamment de la qualité de l’application. La décision est provoquée par l’épuisement des ressources allouées au test ou l’expiration du délai fixé.
Avec l’expérience, le gestionnaire de test dispose de critères qui vont l’aider dans la décision d’arrêter les tests. Ces critères vont lui permettre, en particulier, d’évaluer les risques liés à l’arrêt du test. Voici des exemples de critères :
- le degré de conformité aux exigences de test permet de savoir si toutes les exigences, ou au moins celles correspondant aux risques les plus élevés, ont été testées.
- La couverture de test du code permet de savoir si toutes les parties du code, y compris le code de gestion d’erreurs et d’exceptions, ont subi au moins une fois le test.
- Le nombre de jeux d’essais prévus, conçus, mis en oeuvre, réussis ou ratés informe sur l’état d’avancement du processus de test.
- Le taux de détection d’erreurs et la stabilisation de ce critère donne une idée raisonnable sur la détection de la plupart des erreurs.
Planification des test
Dans l’approche procédurale :
Démarche de test
Un test est toujours réalisé selon les 3 étapes :
- Élaboration des jeux d’essais.
- Réalisation du test.
- Analyse des résultats.
Approches de test
Il existe 3 approches pour conduire un test :
- Approche ascendante.
- Approche descendante.
- Approche incrémentale.
Techniques de tests
Les tests effectués dans les différentes phases sont réalisés en utilisant différentes techniques. Ces techniques peuvent être réparties en 3 catégories : techniques générales, techniques fonctionnelles et techniques non fonctionnelles.
Techniques générales
Test par affirmation/négation
Ce sont 2 techniques complémentaires. Le test par affirmation vise à vérifier la conformité de l’application aux exigences formulées. Les jeux de test sont habituellement conçus en analysant la spécification des exigences. C’est une des techniques utilisées pour s’assurer que l’application a atteint les objectifs fixés.
Le test par négation vise à démontrer que l’application n’agit pas comme elle n’est pas censée le faire. Pour cela, on étudie le comportement de l’application en dehors du cadre fixé par les spécifications. C’est une technique utilisée pour examiner les aspects de l’application non décrits, manquants ou mal formulés.
Test de boite blanche/boite noire
Ce sont également 2 techniques complémentaires. Le choix de l’une ou l’autre des techniques dépend du niveau de connaissance de la structure interne de l’application par l’analyste de test.
Le test de boite blanche, appelé aussi test structurel, s’appuie sur des informations portant sur la structure interne de l’application ou du composant à tester. Connaissant cette structure, l’analyste de test construira le jeu de test de manière à vérifier toute la logique interne. Par exemple, pour tester une fonction contenant une structure si … alors … sinon…, le jeu de test permettra de vérifier le fonctionnement correct de la branche du si et celle du sinon.
Le test de boite noire, appelé aussi test comportemental, à l’opposé, ne suppose aucune connaissance sur la structure interne. Ce sera le cas par exemple lorsqu’on fait le test de recette d’une application achetée, donc développée par des programmeurs tiers avec lesquels on n’a aucun contact (c’est une méthode de choix de logiciel). Ce sera le cas aussi lorsqu’on veut effectuer des tests de régression pour tester l’extension d’une application héritée, sur laquelle la documentation est manquante.
Le test de boite blanche est souvent utilisé par le programmeur lors de test unitaires des composants qu’il construit.
Le test de boite noire est souvent utilisé par l’analyste de test lors de phases ultérieures, comme le test système ; l’analyste de test n’ayant pas accès aux informations structurelles car les composants sont écrit par une équipe tierce.
Souvent, l’analyste mélange les 2 techniques en suivant une méthode qu’on peut qualifier de boite grise.
Techniques fonctionnelles
Analyse partitionnelle
Il s’agit de répartir, lorsque c’est possible, les entrées et les sorties en catégories cohérentes constituant des classes (pas au sens de l’orienté objet). On choisit ensuite un représentant de chaque classe. On émet ainsi l’hypothèse selon laquelle la réussite du test sur un représentant équivaut à sa réussite sur tous les éléments de la classe.
Le secret de la réussite de cette technique réside dans l’identification des classes, du choix des représentants et dans le choix du nombre d’éléments à examiner.
Test aux limites
Cette technique est complémentaire à la précédente et se fonde sur le même principe de répartition des entrées et sorties en classes. Cependant, le test est axé sur les extrêmes des classes.
L’analyse partitionnelle et le test aux limites sont souvent utilisés conjointement pour créer des jeux de test complets.
Test intrusif
Il s’agit de modifier délibérément l’application pour les besoins du test. C’est ce qu’on fait en introduisant le fameux System.out.println (ou équivalent) afin de visualiser les valeurs de certaines variables à l’exécution.
On peut aussi utiliser un débogueur pour modifier les valeurs de variables à l’exécution pour étudier le comportement de l’application.
Le risque avec cette technique est d’oublier de supprimer les modifications introduites et de livrer ainsi au client un produit altéré.
Test de transition d’état
Cette technique consiste à représenter les différents états possibles de l’application (ou du composant à tester), les transitions entre ces états, les événements déclenchant les transitions et les actions résultant de ces transitions.
Les jeux d’essais sont extraits de la spécification de l’application et des diagrammes de transition d’états (utilisés en UML).
Les jeux d’essais sont conçus pour activer les différentes transitions d’état et préciser :
- l’état de départ,
- les entrées dans l’application,
- les résultats attendus,
- l’état final attendu.
Cette technique est utilisée, en particulier, lors du test par affirmation/négation.
Test statique
Dans ce test, l’application n’est pas exécutée. Il s’agit de vérifier l’application en situation isolée. Plusieurs méthodes et outils sont utilisés :
- revue et vérification du code
- exécution manuelle (avec un papier et un crayon)
- outils d’analyse syntaxiques
- outils d’estimation de complexité.
Cette technique est souvent utilisée lors du test unitaire.
Test de navigation
Cette technique, appelée aussi test d’exécution, permet d’évaluer la fonctionnalité ou la logique métier de l’application de bout en bout. L’application, ou le composant, est mise en oeuvre pour réaliser une fonctionnalité étape par étape, de bout en bout. Au lieu de s’intéresser au fonctionnement correct de l’application, on s’intéresse à la logique mise en oeuvre.
Tests unitaires
Exemple de jeu de tests
# | a | b | c | Description | Résultat attendu | Résutat obtenu | Analyse et commentaires |
---|---|---|---|---|---|---|---|
1 | 0 | 0 | 0 | a,b,c = 0 | Infinité | ||
2 | 0 | 0 | -3 | a,b=0, c!=0 | Pas de solution | ||
3 | 0 | 0 | 5 | a,b=0, c!=0 | Pas de solution | ||
4 | 0 | 2 | 0 | 1er degré | Une solution | ||
5 | 0 | -4 | 0 | 1er degré | Une solution | ||
6 | 0 | 3 | 3 | 1er degré | Une solution | ||
7 | 0 | -7 | 5 | 1er degré | Une solution | ||
8 | 0 | 5 | -1 | 1er degré | Une solution | ||
9 | 0 | -1 | -2 | 1er degré | Une solution | ||
0 | 0 | 1 | 4 | D < 0 | Pas de solution | ||
1 | 5 | 0 | 1 | D < 0 | Pas de solution | ||
2 | 1 | 1 | 0 | D > 0 | Deux solutions x=0, x=1 | ||
3 | 1 | 2 | 1 | D = 0 | Une solution | ||
4 | 4 | 12 | 9 | D = 0 | Une solution |
Source : A. Toudeft.