Des dev et des tests
Date de publication : 22 novembre 2010
Par
Thierry Leriche-Dessirier (www.thierryler.com)
Tous les acteurs du développement s'accordent sur l'importance de
tester les applications. On parle de qualité totale, de tests
unitaires, de tests de charge, de couverture de code, de test de non
régression, etc. Pourtant les tests sont, d'expérience, parmi les
premiers à faire les frais des budgets limités. On les accuse de
couter cher, d'être longs à écrire et/ou à maintenir, pour finalement
les mettre au rancard. C'est une grave erreur car des tests bien
pensés augmentent considérablement la productivité de l'ensemble des
étapes des projets. L'éventail des types et topologies de tests est
relativement vaste et permet aux équipes de trouver les solutions
adaptés à la plupart de leurs besoins. Cet article présente une
sélection d'outils importants, dans le cadre des stratégies de test,
dans laquelle chaque projet gagne à puiser son inspiration.
I. Intro
II. Méthodologie
II-A. TDD
II-B. Coût des tests
III. Tests unitaires avec JUnit
IV. Le printemps (Spring) dans les tests
V. Une base de données en mémoire avec DBUnit
VI. Des bouchons avec Mockito
VII. Des simulacres avec EasyMock
VIII. Tests d'intégration
IX. Non régression (NR) avec Selenium
IX-A. Selenium IDE
IX-B. Coté Java, local/remote
IX-C. Pour la recette
X. Des rapports avec Maven et Sunfire
XI. La couverture de test avec Cobertura
XII. Vie, évolution et mort des tests
XIII. Conclusions
XIV. Annexes
I. Intro
TODO
II. Méthodologie
TODO
II-A. TDD
TODO
II-B. Coût des tests
TODO
III. Tests unitaires avec JUnit
JUnit est un framework dédié aux tests unitaires. C'est sans aucun doute le framework de test le plus
connu et le plus utilisé, au point qu'on assimile souvent (à tord) JUnit aux tests de manière générale.
Il est impossible de faire l'impasse sur JUnit tellement le framework est au cœur des stratégies de
développement mais également parce qu'il est mis en œuvre par la plupart des mécanismes de test.
L'objectif des tests unitaires est de valider le bon fonctionnement des fonctionnalités des programmes
de manière autonomes. Une classe de test spécifie le jeu de test et contrôle que les traitements sont
correcte. Un test unitaire s'auto suffit et ne doit surtout pas dépendre d'un élément externe comme un
web service ou la base de données.
Dans les projets modernes, il suffit d'indiquer une dépendance à JUnit dans le fichier pom.xml en précisant
un scope de test.
Dépendance à JUnit dans le pom |
< dependency >
< groupId > junit< / groupId >
< artifactId > junit< / artifactId >
< version > 4.8< / version >
< scope > test< / scope >
< / dependency >
|
Comme pour n'importe quelle dépendance, il suffit de demander à Maven de générer la configuration pour utiliser
JUnit dans Eclipse.
Maven et Eclipse |
mvn eclipse:eclipse
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'eclipse'.
[INFO] ------------------------------------------------------------------------
[INFO] Building dev-et-tests
[INFO] task-segment: [eclipse:eclipse]
[INFO] ------------------------------------------------------------------------
[INFO] Preparing eclipse:eclipse
[INFO] No goals needed for project - skipping
[INFO] [eclipse:eclipse {execution: default-cli}]
[INFO] Using Eclipse Workspace: null
[INFO] Adding default classpath container: org.eclipse.jdt.launching.JRE_CONTAINER
[INFO] File D:\javadev\article\developpez.com\dev-et-tests\.project already exists.
Additional settings will be preserved, run mvn eclipse:clean if you want old settings to be removed.
[INFO] Wrote Eclipse project for "dev-et-tests" to D:\javadev\article\developpez.com\dev-et-tests.
[INFO]
Sources for some artifacts are not available.
Please run the same goal with the -DdownloadSources=true parameter in order to check remote repositories for sources.
List of artifacts without a source archive:
o junit:junit:4.8.1
Javadoc for some artifacts is not available.
Please run the same goal with the -DdownloadJavadocs=true parameter in order to check remote repositories for javadoc.
List of artifacts without a javadoc archive:
o junit:junit:4.8.1
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Tue Dec 28 20:17:12 CET 2010
[INFO] Final Memory: 8M/21M
[INFO] ------------------------------------------------------------------------
|
 |
Dans un projet Maven, les classes Java sont placées dans le dossier "src/main/java" et les classes de test
dans le dossier "src/test/java".
|
Pour réaliser des tests, encore faut-il avoir quelque chose à tester. Une bonne pratique, comme dans le cadre
d'une stratégie DDT (Développement Dirigé par les Tests), consiste à écrire en premier les interfaces des programmes,
puis les tests utilisant ces interfaces, en précisant les données d'entrée et les résultats attendus, puis finalement de programmer
les implémentations à proprement dit.
Un simple programme de calculette fera un très bon exemple. En voici l'interface initiale.
Interface d'une calculette |
public interface Calculette {
int add (int a, int b);
int multiply (int a, int b);
}
|
Les classes de test sont, par convention, postfixées par "Test" ou "TestCase" et exposent des méthodes
"public void" annotées par "@Test". En général, on écrit au moins une méthode de test pour chaque méthode de l'interface
à valider.
Classe de test |
import junit.framework.Assert;
import org.junit.Test;
public class CalculetteTestCase {
private Calculette calculette;
@ Test
public void testAdd () {
final int a = 2 ;
final int b = 3 ;
int result = calculette.add (a, b);
Assert.assertEquals (5 , result);
}
@ Test
public void testMultiply () {
final int a = 2 ;
final int b = 3 ;
int result = calculette.multiply (a, b);
Assert.assertEquals (6 , result);
}
}
|
La méthode "Assert.assertEquals()" permet de comparer une valeur attendue avec le résultat (réel) d'une
méthode.
A ce stade, il est temps d'écrire l'implémentation de la calculette.
Implémentation de la calculette |
public class DefaultCalculette implements Calculette {
@ Override
public int add (int a, int b) {
return a + b;
}
@ Override
public int multiply (int a, int b) {
return a * b;
}
}
|
Cette implémentation peut ensuite être utilisée par les tests. Pour cela il faut compléter CalculetteTestCase
avec la méthode setUp(), nommée ainsi par convention à cause des anciennes versions de JUnit, et annotée
par @Before. Cette méthode est appellée automatiquement avant chaque test, étant dit que chaque méthode annotée
avec @Test définit un test. Dans l'exemple, la méthode setUp() sera donc appellée 2 fois.
Méthode setUp() annotée @Before |
public class CalculetteTestCase {
private Calculette calculette;
@ Before
public void setUp () {
calculette = new DefaultCalculette ();
}
|
IV. Le printemps (Spring) dans les tests
TODO
V. Une base de données en mémoire avec DBUnit
TODO
VI. Des bouchons avec Mockito
TODO
VII. Des simulacres avec EasyMock
TODO
VIII. Tests d'intégration
TODO
IX. Non régression (NR) avec Selenium
TODO
IX-A. Selenium IDE
TODO
IX-B. Coté Java, local/remote
TODO
IX-C. Pour la recette
TODO
X. Des rapports avec Maven et Sunfire
TODO
XI. La couverture de test avec Cobertura
TODO
XII. Vie, évolution et mort des tests
TODO
XIII. Conclusions
TODO
XIV. Annexes
TODO


Les sources présentées sur cette page sont libres de droits
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ©
2010 Thierry Leriche-Dessirier. Aucune reproduction, même partielle, ne peut être
faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc.
sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à
trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.