• Aucun résultat trouvé

Plan. Tests. 1. Introduction. 1. Introduction

N/A
N/A
Protected

Academic year: 2022

Partager "Plan. Tests. 1. Introduction. 1. Introduction"

Copied!
11
0
0

Texte intégral

(1)

Tests 1 Lionel Seinturier

Tests

Lionel Seinturier

Université des Sciences et Technologies de Lille

[email protected]

28/11/06

Tests 2 Lionel Seinturier

Plan

1. Introduction 2. Tests unitaires 3. Éléments à tester 4. Anti-patterns de test 5. Test et modularité du code 6. Organisation de projet

1. Introduction

Objectifs du test de programmes

Détecter des erreurs dans un programme

"Testing is the process of executing a program with the intent of finding errors"

[Myers: The Art of Software Testing. 1979]

Autres techniques pour valider un programme

• preuve : modélisation formelle + établissement de théorèmes

• vérification : ex model-checking

Tests : + facile à appréhender, + proche du code, - coûteux à mettre en oeuvre Mais

• ne garantît pas que le programme est exempt d'erreur

• on ne teste que ce à quoi on a pensé

"Program testing can be used to show the presence of bugs, but never to show their absence!" [Edsger Dijkstra]

1. Introduction

Objectifs du test de programmes

Les tests sont importants (∀monde d'accord)

mais les tests tendent à être répoussés à la fin d'un projet

¾plus une erreur est découverte tard, plus elle coûte cher

L'écriture de test n'est une tâche dévolue

¾ni aux utilisateurs, ni aux managers, ni aux chefs de projet

¾c'est vraiment une activité de programmeur

(2)

Tests 5 Lionel Seinturier

1. Introduction

Différentes catégories de tests

• boîte blanche

• boîte noire Tests boîte blanche

• on a accès à la structure du code

• ex. : calcul de tous les chemins d'exécution possibles (branches, instructions, …)

• tests sur chacun de ces chemins

• avantage : on peut détecter des situations extrèmes qui ne se manifestent que dans certaines branches

• inconvénients

• calcul des chemins souvent long

• il faut avoir accès au code source

Tests 6 Lionel Seinturier

1. Introduction

Différentes catégories de tests

• boîte blanche

• boîte noire Tests boîte noire

• les + courants

• aucune connaissance des détails d'implémentation n'est nécessaire

• on s'en remet à la spécification

on vérifie que l'implémentation fournit bien le résultat attendu par la spéc

1. Introduction

Différentes granularités de tests

unitaire, intégration, système, recettes Tests unitaires

• test d'une "unité logicielle"

procédural Öprocédure

OO Öméthode

• test indépendant des autres unités

• les + faciles à mettre en oeuvre

• les + fréquents

• nombreux frameworks disponibles

• Java : JUnit, Cactus, TestNG, JTiger, …

• wikipedia : +90 frameworks !! dans 35 langages ≠

1. Introduction

Différentes granularités de tests

Tests d'intégration

• test du comportement d'un ensemble d'unités

• principales techniques : bouchon de tests, mock objects

•≠frameworks : Easy Mock, jMock, Mocquer

s'utilisent en complément/avec les frameworks de tests unitaires Tests système

• tests de l'intégration d'une application complète avec son env. d'exécution (OS, VM, librairies, serveurs, …)

Tests de recettes

• tests effectués en présence du client afin de valider l'application complète

(3)

Tests 9 Lionel Seinturier

1. Introduction

Éventail de tests possibles

Tests 10 Lionel Seinturier

1. Introduction

Différentes techniques d'écriture de tests

Écriture manuelle

• par le programmeur, ou celui qui connaît la spécification

• cas le plus fréquent Génération automatique

• "force brute"

• ex : JCrasher

• outil d'évaluation de la robustesse d'un prog.

• génère des séquences aléatoires d'appels de méthodes

• dans le but de détecter celles qui font planter le programme

• par mutation de tests existants

• on fait varier les paramètres des tests existants

• afin de détecter les conditions non couvertes par les tests

• à partir de spécifications formelles du programme

1. Introduction

Écriture de programmes testables

Pour qu'un programme soit "facilement" testable

• il faut (souvent) prévoir l'accès à l'état Öajout de setter/getter

• il faut éviter au maximum les effets de bord

ex. : lecture au clavier, écriture à l'écran, dans un fichier Öséparer en 2 parties

• une méthode avec la fonctionnalité à tester

• une méthode avec les effets de bord qui appelle la précédente Ösouvent refactorisation de l'application pour accéder éléments à tester Ömieux : penser à la testabilité en écrivant le programme

1. Introduction

Sélection du code à tester

• tester les conditions aux limites

• paramètre null, tableau vide, valeurs max, min, …

• tester les "grandes catégories" (classes d'équivalence) de comportements

• dans tels cas, la méthode lève une exception

• dans tels cas, la méthode retourne null

• dans tels cas, la méthode retourne une valeur particulière

• tester les invariants du programme

• propriété à conserver après chaque opération de modification

•≠catégories

• structurels : ex. : index d'une liste ∈[0..taille_liste]

• sémantiques : ex. : une liste (auto)-triée doit rester triée

• cohérence de données

• ex. : ∑dépôts + ∑retraits = solde

• ex. : prix TTC = prix HT * TVA

(4)

Tests 13 Lionel Seinturier

1. Introduction

Sélection du code à tester

• tester les invariants du programme

• cohérence de données

• ex. : même donnée stockée à≠endroits du programme dans la même unité ou des unités (cm, inch) ≠

• intégrité référentielle

• ex. : vérifier que la bidirectionalité dans une association est conservée

• tester que les préconditions des méthodes sont respectées

• tester que les postconditions des méthodes sont respectées

Tests 14 Lionel Seinturier

1. Introduction

Sélection du code à tester

Ölien avec la notion d'assertion / contrat

• notion introduite dans le langage Eiffel [Meyer 85]

¾programming / design by contract

•≠mises en oeuvre en Java

• instruction assert(à partir JDK 1.4)

• frameworks Contract4J, Jass, jContractor, JML, … Contrats vs tests

• contrats

• intrusifs (certes débraillables) : vérifier sur une application qui s'exécute

• utiles si les conditions d'exécution sont difficilement reproductibles

• tests

off-line

• ne modifient pas l'application

• prise en compte + facile de nombreux scenarii d'exécution

1. Introduction

Sélection du code à tester

• on n'écrit pas forcément 1 test / méthode du programme

• pas de test pour

• setter/getter

• méthode de 2 lignes, …

• ce que l'on cherche à tester

• les "services" rendus par une classe

1. Introduction

Mesure de la qualité des tests

Notion de couverture de code (coverage)

Ö% de code couvert par des tests (unitaires, intégration, …)

Öon cherche à vérifier que chaque ligne d'un programme est couvert par au moins un test

Öne garantît pas la correction

Öindicateur sur le "sérieux" d'un ensemble de tests

≠formes

• % de méthodes, branches, lignes, instructions

≠outils

• Cobertura, EMMA, Patchwork, Quilt, …

(5)

Tests 17 Lionel Seinturier

2. Tests unitaires

Test unitaire

Code qui évalue le comportement d'une fonctionnalité

¾la fonctionnalité testée est souvent de granularité fine

¾accumulation de tests de "petites portions" d'un programme Exemples

fonctionnalité : ajouter une valeur à une liste (auto)-triée test : vérifier qu'une "grande" valeur est bien placée à la fin fonctionnalité : supprimer un pattern dans une chaîne de caractères test : vérifier que le pattern n'y est plus

¾"prouve" que la fonctionnalité fait ce qu'elle est censée faire

¾augmente la confiance dans la correction de la fonctionnalité

¾on est plus enclin à la réutiliser

¾facilite l'intégration

Tests 18 Lionel Seinturier

2. Tests unitaires

Test unitaire

comportement : code

test : code

Code du test

• plus petit que le code du comportement à tester

• ne contient pas de complexité algorithmique (source d'erreurs)

• souvent de la forme

• appel méthode + paramètres d'entrées

• vérification résultat attendu est bien le bon

2. Tests unitaires

Questions auxquelles permettent de répondre des tests unitaires

• est-ce que mon code fait ce que je veux qu'il fasse ?

• est-ce qu'il le fait dans toutes les conditions ?

• pas seulement dans le cas nominal standard

• mais aussi en présence d'exception, de buffer overflow, …

• aux conditions limites(valeurs, charge, …)

• avantage collatéral des tests

¾ils traduisent l'intention du programmeur

≈spécification light

Plan

1. Introduction

2. Tests unitaires

3. Éléments à tester

4. Anti-patterns de test

5. Test et modularité du code

6. Organisation de projet

(6)

Tests 21 Lionel Seinturier

3. Éléments à tester

Que tester ?

• "tout ce qui est susceptible de provoquer un plantage" …

• principe Right-BICEP

• Right : est-ce que les résultats sont corrects ?

• B (Boundary) : est-ce que les conditions aux limites sont correctes ?

• I (Inverse) : est-ce que l'on peut vérifier la relation inverse ?

• C (Cross-check) : est-ce que l'on peut vérifier le résultat autrement ?

• E (Error condition) : est-ce que l'on peut forcer l'occurrence d'erreurs ?

• P (Performance) : est-ce que les performances sont prévisibles ?

Tests 22 Lionel Seinturier

3. Éléments à tester

Right

• validation des résultats en fonction de ce que définit la spécification

• on doit pouvoir répondre à la question

• comment sait-on que le programme s'est exécuté correctemment ?

• si pas de réponse Öspécifications certainement vagues, incomplètes

• la notion de correction peut évoluer au cours du temps

• en fonction de l'évolution des besoins, des spécifications, …

• tests = traduction des spécifications

3. Éléments à tester

Boundary conditions

• identifier les conditions aux limites de la spécification

• que se passe-t-il lorsque les données sont

• anachroniques ex. : !*W@\/"

• non correctement formattées ex. : fred@foobar.

• vides ou nulles ex. : 0, 0.0, "", null

• extraordinaires ex. : 10000 pour l'age d'une personne

• dupliquées ex. : doublon dans un Set

• non conformes ex. : listes ordonnées qui ne le sont pas

• désordonnées ex. : imprimer avant de se connecter

• principe "CORRECT"

• conformance, ordering, range, reference, existence, cardinality, time

3. Éléments à tester

Boundary conditions

Conformance

• données doivent souvent respecter un format bien particulier

• format de fichier, email (voir RFC 822), URL, …

• tester les cas où les données ne respectent pas le format Ordering

• l'ordre des données dans une structure peut avoir de l'importance

• tester les cas où l'ordre n'est pas respecté Range

• situation où une donnée a moins de valeurs légales que son type

• ex. int angle Ö0..359

• invariants : le # de données dans un buffer fini ∈tjrs à [0..max]

• tester les valeurs qui sont en dehors de l'intervalle

(7)

Tests 25 Lionel Seinturier

3. Éléments à tester

Boundary conditions

Reference

• les dépendances de la méthode à tester avec le reste de l'application

• pré et post-conditions

• ex. : ne pouvoir faire pop() sur une pile vide

• cf. les diagrammes états/transitions

• tester ce qui n'est pas dans le diagramme Existence

• que se passe-t-il lorsque la valeur attendue n'existe pas ?

• pas de Client associé à une Facture Cardinality

• que se passe-t-il avec les valeurs "remarquables" ?

• 0, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE, …

Tests 26 Lionel Seinturier

3. Éléments à tester

Boundary conditions

Time

• les cas où l'ordre dans le temps à de l'importance

• ex. : pas de logout() avant login()

3. Éléments à tester

Inverse – Cross-check

Identifier

• les relations inverses

• les algorithmes équivalents (cross-check) qui permettent de vérifier le comportement

public void testSquareRootUsingInverse() { double x = mySquareRoot(4.0);

assertEquals( 4.0, x*x, 0.0001 );

}

public void testSquareRootUsingStd() { double x1 = mySquareRoot(4.0);

double x2 = Math.sqrt(4.0);

assertEquals( x2, x1, 0.0001 );

}

3. Éléments à tester

Error condition – Performance

Que se passe-t-il en cas de

• disque, mémoire, … plein

• perte de connexion réseau

Est-ce que le système réagit de façon non exponentielle à une montée en charge ? ex. : vérifier qu'un élément n'est pas dans une liste

• vérifier que le temps est linéaire avec la taille de la liste

• application continue de répondre en présence d'une surcharge du système ?

¾quasiment un domaine à part entière

¾nombreux frameworks d'injection de charge et d'identification des parties d'application coûteuses (Eclipse TPTP, ObjectWeb, CLIF, …)

(8)

Tests 29 Lionel Seinturier

Plan

1. Introduction 2. Tests unitaires 3. Éléments à tester 4. Anti-patterns de test 5. Test et modularité du code 6. Organisation de projet

Tests 30 Lionel Seinturier

4. Anti-patterns de test

Anti-patterns de test

Anti-pattern

• le contraire d'un pattern

• les mauvaises pratiques à éviter

• assert manquant

• asserts multiples

• utilisation du mauvais assert

• test trop compliqué

• dépendances externes

• récupération d'exceptions non prévues

4. Anti-patterns de test

Anti-patterns de test

Assert manquant

• un test qui ne teste rien Öinutile dans 99% des cas

• 1% : pas de résultat attendu, mais vérification qu'il n'y a pas d'exception

• utilité : non regression par rapport à un bug précédent

Asserts multiples

• pas une bonne idée

• les tests doivent rester courts

• + facile à comprendre

• + facile d'identifier les causes des erreurs détectées par les tests

• - de risque d'erreur dans les tests

• si besoin de partage de code entre parties à tester ÖsetUp

4. Anti-patterns de test

Anti-patterns de test

Asserts multiples

public void testSomething() { // ...

assertTrue(condition1);

assertTrue(condition2);

assertTrue(condition3);

}

public void setUp() { // ...

}

public void testSomething1() { assertTrue(condition1);

}

public void testSomething2() { assertTrue(condition2);

}

public void testSomething3() { assertTrue(condition3);

}

(9)

Tests 33 Lionel Seinturier

4. Anti-patterns de test

Anti-patterns de test

Utilisation du mauvais assert

• appel à assertTrue avec un true codé en dur : non

assertTrue( "Object must be the same", expected == actual );

assertTrue( "Objects must be equals", expected.equals(actual) );

assertTrue( "Object must be null", actual == null );

assertTrue( "Object must be non null", actual != null );

• utiliser l'assert correspondant

assertSame( "Object must be the same", expected, actual );

assertEquals( "Objects must be equals", expected, actual );

assertNull( "Object must be null", actual );

assertNotNull( "Object must be non null", actual );

¾plus clair

¾précise l'intention du testeur

Tests 34 Lionel Seinturier

4. Anti-patterns de test

Anti-patterns de test

Test trop compliqué

• il ne faut pas avoir à tester le test pour se convaincre qu'il est bon

Dépendances externes

• éviter les dépendances vers l'environnement

• SGBD, fichiers, librairies, socket, …

• il ne faut qu'il y ait des éléments trop compliqués à mettre en place Ösinon les tests ne seront pas exécutés

¾utiliser des mocks pour remplacer les librairies

¾faire en sorte d'inclure toutes les données nécessaires avec les tests

¾s'il faut vraiment un SGBD, envisager l'emploi de SGBD en mémoire (par ex. HSQLDB)

4. Anti-patterns de test

Anti-patterns de test

Récupération d'exceptions

• code "normal" Örécupérer les exceptions

• tests Önon

public void testCalculation() { try {

deepThought.calculate();

assertEquals("Calculation wrong", 42, deepThought.getResult());

}

catch(CalculationException ex) {

Log.error("Calculation caused exception", ex);

} }

¾raté ! JUnit ne détectera pas que le test a échoué

4. Anti-patterns de test

Anti-patterns de test

Récupération d'exceptions

• 2ème essai

public void testCalculation() { try {

deepThought.calculate();

assertEquals("Calculation wrong", 42, deepThought.getResult());

}

catch(CalculationException ex) {

Log.error("Calculation caused exception", ex);

fail("Calculation caused exception");

} }

¾encore raté !

¾test échoue effectivement mais on perd la source de l'erreur (StackTrace)

(10)

Tests 37 Lionel Seinturier

4. Anti-patterns de test

Anti-patterns de test

Récupération d'exceptions

• la bonne solution

public void testCalculation() throws CalculationException { deepThought.calculate();

assertEquals("Calculation wrong", 42, deepThought.getResult());

}

¾les exceptions sont ce qui est recherché par les tests

Tests 38 Lionel Seinturier

Plan

1. Introduction 2. Tests unitaires 3. Éléments à tester 4. Anti-patterns de test 5. Test et modularité du code 6. Organisation de projet

5. Test et modularité du code

Concevoir/refactoriser en vue du test

Séparer les préoccupations Une préoccupation

• un ensemble de fonctionnalités ayant un lien logique entre elles

• notion

• floue : plus un principe, une "idée" qu'une définition formelle

• variable : en fonction des développeurs, des besoins, de l'évolution Exemple

• application de gestion de clientèle

• ajouter/supprimer clients

• gérer données client

• affichage graphique GUI

• sauver/restaurer les données dans un fichier

5. Test et modularité du code

Concevoir/refactoriser en vue du test

Séparer les préoccupations

(11)

Tests 41 Lionel Seinturier

5. Test et modularité du code

Concevoir/refactoriser en vue du test

Séparer les préoccupations

• pouvoir tester les différentes parties sans avoir à se préoccuper du reste

• plus le programme est modulaire

• plus il est facile à appréhender, concevoir, tester

• plus les erreurs sont facilement identifiables

• écriture des tests

¾occasion de refactoriser

¾bénéficie aussi en terme de conception

Tests 42 Lionel Seinturier

6. Organisation de projet

S'organiser pour faciliter la testabilité

• 1 classe de test par classe à tester

• nom des classes de test

• le même que la classe à tester préfixé par Test

• les classes de test

• dans le même package

• mais dans des hiérarchies de répertoire //

src/org/foo/MaClasse.java test/org/foo/TestMaClasse.java

• fréquence d'exécution des tests

• chaque fois qu'une nouvelle classe / méthode significative est ajoutée

• à chaque résolution de bug

• en cas de travail collabortif (CVS/SVN, …)

• à chaque récupération des mises à jour à partir du référentiel

• éventuellement périodiquement (gros projets)

6. Organisation de projet

Tests dits de non régression

• chaque découverte de bug doit donner lieu à l'écriture d'un test caractérisant le bug

¾objectif : faire en sorte que le bug ne réapparaisse pas ultérieurement (non régression)

Tests et logiciels patrimoniaux (legacy)

• a priori non conçus pour les tests

• écrire des tests

• pour les fonctionnalités critiques

• pour les fonctionnalités dont on sait qu'elles sont mal écrites (donc les + susceptibles de provoquer des erreurs)

• en fonction des bugs découverts (non regression)

Bibliographie

A. Hunt, D. Thomas. Pragmatic Unit Testing. 2004.

G. Myers, C. Sandler, T. Badgett, T. Thoma. The Art of Software Testing.

2nd Edition.

http://en.wikipedia.org/wiki/Software_testing http://www.junit.org

http://www.easymock.org http://jakarta.apache.org/cactus

Références

Documents relatifs

Le design de contrˆoleurs dans l’espace d’´etat permet de sp´ecifier compl`etement les pˆoles d’un syst`eme, pour obtenir la r´eponse temporelle voulue?. Pour les contrˆoleurs

SAVOIR ÉCOUTER SAVOIR ÉCRIRE MATHÉMATIQUES GRANDEURS SOLIDES ET FIGURES ÉVEIL INITIATION FORMATION HISTORIQUE ET GÉOGRAPHIQUE NOMBRES ET OPÉRATION CEB 2015 FRANÇAIS

De cette périodisation, dans laquelle, pour employer un vocabulaire peut-être anachronique, la dépolitisation progressive des fonctions va de pair avec leur socialisation,

Cette période permettra le peaufinage des méthodes tant d’édition du génome, que de détection 

Reconstitue le titre de l'histoire lue en classe en écriture scripte.. Repasse sur les mots en cursive en t'aidant

d) Bilan des valeurs des paramètres du modèle de GREEN-AMPT (sol sous la croûte) 3) Fixation des paramètres de calcul de l’infiltrabilité du sol.

a) Le propriétaire de la fabrique est respon- sable des dommages causés, si un mandataire, représentant, directeur ou surveillant de la fa- brique a, dans l'exercice de ses

Ö La rivière est forcée d'entrer dans l'ouvrage de dérivation par une surélévation du plan