I. INTRODUCTION▲
Pour une compréhension aisée de cet article, il est conseillé d'avoir quelques connaissances en Java, JUnit (de version précédente) et Eclipse.
JUnit est un framework de tests unitaires pour Java. Ce framework appartient à l'ensemble des frameworks de tests xUnit. Ce framework a été écrit par Kent Beck (en autre créateur de l'Extreme Programming et du framework de tests SUnit pour Smalltalk, qui a inspiré tous les autres xUnit) et Erich Gamma (entre autres un des quatre auteurs de Design Patterns: Elements of Reusable Object-Oriented Software et concepteur de Java Development Tools, la partie d'Eclipse supportant Java).
Depuis Java 5, d'importantes évolutions ont été apportées à JUnit. Les dernières versions de JUnit ont donc changé de numéro majeur de version pour passer de JUnit 3.x à JUnit 4.x.
Cet article va présenter les particularités que JUnit4 (et plus particulièrement la version 4.5) apporte par rapport à JUnit3 :
- les annotations pour les tests ;
- les nouvelles assertions ;
- les suppositions ;
- les tests paramétrés ;
- les annotations pour les suites de tests.
Lors de mes recherches, j'ai remarqué que parfois les imports statiques étaient considérés comme une évolution de JUnit4. Il s'agit cependant d'une évolution entièrement liée à Java5. J'ai tendance à ne pas les utiliser dans l'article, non par conviction anti« imports statiques » ;-), mais parce que j'ai pensé que ça serait plus lisible dans l'article. Il y a cependant quelques exemples avec des imports statiques.
Pour la réalisation de cet article, les versions des outils sont :
II. AUTRES RESSOURCES SUR DEVELOPPEZ.COM▲
FAQ Eclipse (Comment utiliser JUnit avec Eclipse ?) ;
FAQ NetBeans (Comment utiliser JUnit avec NetBeans ?) ;
Tests unitaires par Sébastien MERIC ;
Conception de tests unitaires avec JUnit par Romain Guy ;
Test unitaire avec Spring par Johnny Beuve ;
Article complet: JUnit Antipatterns sur ady's blog ;
Chapitre 11 (JUnit et Eclipse) de Développons en Java avec Eclipse par Jean-Michel DOUDOUX ;
Chapitre 67 (Les frameworks de tests) de Développons en Java avec Eclipse par Jean-Michel DOUDOUX.
III. LES ANNOTATIONS POUR LES TESTS▲
Les annotations sont en Java une nouveauté de Java 5. Les annotations de JUnit apportent des fonctionnalités en plus (initialisation globale à l'ensemble des méthodes de tests d'un cas de test) et de la souplesse. Il n'est plus nécessaire que le cas de tests soit une classe héritant de TestCase. Les annotations indiquent le comportement du cas de tests. Toutes les annotations, ci-après, sont apparues à partir de la version 4.0 de JUnit.
III-A. Test simple▲
La javadoc de cette annotation est disponible ici.
Pour déterminer les méthodes de tests, JUnit3 recherche toutes celles commençant par « test » dans les classes héritant de TestCase. JUnit4, quant à lui, recherche les méthodes avec l'annotation @Test dans n'importe quelle classe.
package
com.developpez.rpouiller.testsjunit4;
public
class
Operations {
public
static
long
additionner
(
final
long
...pNombres) {
long
lRetour =
0
;
for
(
final
long
lNombre : pNombres) {
lRetour +=
lNombre;
}
return
lRetour;
}
// Cette méthode ne fonctionne pas correctement
// Les tests vont le vérifier
public
static
long
multiplier
(
final
long
...pNombres) {
long
lRetour =
0
;
for
(
final
long
lNombre : pNombres) {
lRetour *=
lNombre;
}
return
lRetour;
}
}
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestSimple {
@Test
public
void
additionAvecDeuxNombres
(
) {
final
long
lAddition =
Operations.additionner
(
10
, 20
);
Assert.assertEquals
(
30
, lAddition);
}
@Test
public
void
additionAvecCinqNombres
(
) {
final
long
lAddition =
Operations.additionner
(
256
, 512
, 1024
, 2048
, 4096
);
Assert.assertEquals
(
7936
, lAddition);
}
@Test
public
void
mutiplicationAvecDeuxNombres
(
) {
final
long
lMultiplication =
Operations.multiplier
(
10
, 20
);
Assert.assertEquals
(
300
, lMultiplication);
}
public
void
testMutiplicationAvecCinqNombres
(
) {
final
long
lMultiplication =
Operations.additionner
(
256
, 512
, 1024
, 2048
, 4096
);
Assert.assertEquals
(
1125899906842624
L, lMultiplication);
}
}
Comme le montre la capture d'écran ci-dessous, seules les méthodes de tests avec l'annotation ont été exécutées.
III-B. Test devant déclencher un Throwable▲
La javadoc de cette annotation est disponible ici.
Cette annotation permet de vérifier qu'un Throwable a bien été déclenché. L'annotation reçoit la classe du Throwable attendu en paramètre.
package
com.developpez.rpouiller.testsjunit4;
public
class
Operations {
public
static
long
diviser
(
final
long
...pNombres) {
if
(
pNombres.length <
2
) {
throw
new
IllegalArgumentException
(
"Il faut au moins deux nombres en entrée"
);
}
long
lRetour =
pNombres[0
];
for
(
int
i=
1
;i<
pNombres.length;i++
) {
lRetour /=
pNombres[i];
}
return
lRetour;
}
}
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.Test;
public
class
TestThrowable {
@Test
(
expected=
IllegalArgumentException.class
)
public
void
divisionAvecUnNombre
(
) {
Operations.diviser
(
1
);
}
@Test
(
expected=
ArithmeticException.class
)
public
void
divisionAvecDeuxNombresDontUnZero
(
) {
Operations.diviser
(
10
, 0
);
}
@Test
(
expected=
ArithmeticException.class
)
public
void
divisionAvecDeuxNombres
(
) {
Operations.diviser
(
10
, 5
);
}
}
Comme le montre la capture d'écran ci-dessous, les deux premières méthodes de test provoquent des Exceptions (la première à cause du contrôle en début de la méthode diviser, la deuxième à cause d'une division par zéro). La dernière ne déclenche pas d'erreur, le test est donc considéré comme échoué.
III-C. Test d'une durée limitée▲
La javadoc de cette annotation est disponible ici.
Cette annotation permet de vérifier qu'un test ne dépasse pas une durée. Au-delà de cette durée, le test passe en erreur. La durée en millisecondes est passée en paramètre à l'annotation.
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.Test;
public
class
TestDureeLimitee {
@Test
(
timeout=
1000
)
public
void
dureeRespectee
(
) {
}
@Test
(
timeout=
1000
)
public
void
dureeNonRespectee
(
) throws
InterruptedException {
Thread.sleep
(
10000
);
}
}
Comme le montre la capture d'écran ci-dessous, lorsque la durée d'un test dépasse la durée indiquée, le test passe en erreur.
III-D. Indisponibilité d'un test▲
La javadoc de cette annotation est disponible ici.
Cette annotation permet de ne pas passer un test.
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.Assert;
import
org.junit.Ignore;
import
org.junit.Test;
public
class
TestIndisponibilite {
@Test
public
void
nonIgnore1
(
) {
}
@Test
public
void
nonIgnore2
(
) {
Assert.fail
(
"Echec"
);
}
@Ignore
@Test
public
void
ignore
(
) {
Assert.fail
(
"Echec ignoré"
);
}
}
Comme le montre la capture d'écran ci-dessous, le premier test est passé avec succès, le deuxième a échoué et le troisième a été ignoré.
III-E. Préparation avant et démontage après chaque test d'un cas de test▲
La javadoc de ces annotations est disponible ici et ici.
Ces annotations permettent d'indiquer une méthode qui sera exécutée avant chaque test et une méthode qui sera exécutée après chaque test.
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.After;
import
org.junit.Before;
import
org.junit.Test;
public
class
TestAvantApres {
@Before
public
void
avantTest
(
) {
System.out.println
(
"------------------------"
);
System.out.println
(
"Avant Test"
);
}
@After
public
void
apresTest
(
) {
System.out.println
(
"Après Test"
);
System.out.println
(
"------------------------"
);
}
@Test
public
void
premierTest
(
) {
System.out.println
(
"Premier Test"
);
}
@Test
public
void
deuxiemeTest
(
) {
System.out.println
(
"Deuxième Test"
);
}
@Test
public
void
troisiemeTest
(
) {
System.out.println
(
"Troisième Test"
);
}
}
Comme le montre la trace ci-dessous, les méthodes avantTest et apresTest sont exécutées avant et après les méthodes de test.
------------------------
Avant Test
Premier Test
Après Test
------------------------
------------------------
Avant Test
Deuxième Test
Après Test
------------------------
------------------------
Avant Test
Troisième Test
Après Test
------------------------
III-F. Préparation avant et démontage après l'ensemble de tests d'un cas de tests▲
La javadoc de ces annotations est disponible à l'URL : ici et ici.
Ces annotations permettent d'indiquer une méthode qui sera exécutée avant l'ensemble des tests d'un cas de tests et une méthode qui sera exécutée après l'ensemble des tests d'un cas de tests.
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.AfterClass;
import
org.junit.BeforeClass;
import
org.junit.Test;
public
class
TestAvantApresEnsemble {
@BeforeClass
public
static
void
avantTests
(
) {
System.out.println
(
"------------------------"
);
System.out.println
(
"Avant Tests"
);
System.out.println
(
"------------------------"
);
}
@AfterClass
public
static
void
apresTests
(
) {
System.out.println
(
"------------------------"
);
System.out.println
(
"Après Tests"
);
System.out.println
(
"------------------------"
);
}
@Test
public
void
premierTest
(
) {
System.out.println
(
"Premier Test"
);
}
@Test
public
void
deuxiemeTest
(
) {
System.out.println
(
"Deuxième Test"
);
}
@Test
public
void
troisiemeTest
(
) {
System.out.println
(
"Troisième Test"
);
}
}
Comme le montre la trace ci-dessous, les méthodes avantTests et apresTests sont exécutées avant et après l'ensemble des méthodes de test.
------------------------
Avant Tests
------------------------
Premier Test
Deuxième Test
Troisième Test
------------------------
Après Tests
------------------------
IV. LES NOUVELLES ASSERTIONS▲
IV-A. Assertions d'égalité pour les tableaux▲
Ces assertions comprennent des assertions d'égalité pour les tableaux de :
- « byte » dont la javadoc est disponible ici et ici ;
- « char » dont la javadoc est disponible ici et ici ;
- « short » dont la javadoc est disponible ici et ici ;
- « int » dont la javadoc est disponible ici et ici ;
- « long » dont la javadoc est disponible ici et ici ;
- « Object » dont la javadoc est disponible ici et ici.
Ces assertions sont présentes dans JUnit depuis la version 4.3.1.
package
com.developpez.rpouiller.testsjunit4;
import
java.util.Arrays;
public
class
Operations {
// Cette méthode vérifie que les longueurs passées en paramètre
// sont celles d'un triangle rectangle
public
static
Boolean[] pythagore
(
final
long
[]...pLongueurs) {
final
Boolean[] lRetours =
new
Boolean[pLongueurs.length];
for
(
int
i=
0
;i<
pLongueurs.length;i++
) {
final
long
[] lLongeurs =
pLongueurs[i];
if
(
lLongeurs.length !=
3
) {
throw
new
IllegalArgumentException
(
"Les blocs de longueurs doivent être de 3 éléments"
);
}
final
long
[] lCopieLongueurs =
lLongeurs.clone
(
);
Arrays.sort
(
lCopieLongueurs);
final
long
lLongueur1 =
lCopieLongueurs[0
] *
lCopieLongueurs[0
];
final
long
lLongueur2 =
lCopieLongueurs[1
] *
lCopieLongueurs[1
];
final
long
lLongueur3 =
lCopieLongueurs[2
] *
lCopieLongueurs[2
];
if
(
lLongueur1 +
lLongueur2 ==
lLongueur3) {
lRetours[i] =
true
;
}
else
{
lRetours[i] =
false
;
}
}
return
lRetours;
}
}
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestTableau {
@Test
public
void
tableauAvecMemesValeurs
(
) {
final
Boolean[] lResutat =
Operations.pythagore
(
new
long
[]{
3
, 4
, 5
}
,
new
long
[]{
6
, 10
, 8
}
);
Assert.assertArrayEquals
(
new
Boolean[]{
true
, true
}
, lResutat);
}
@Test
public
void
tableauAvecValeursDifferentes
(
) {
final
Boolean[] lResutat =
Operations.pythagore
(
new
long
[]{
3
, 4
, 6
}
,
new
long
[]{
6
, 11
, 8
}
);
Assert.assertArrayEquals
(
new
Boolean[]{
true
, true
}
, lResutat);
}
}
Comme le montre la capture d'écran ci-dessous, l'assertion vérifie que les éléments des tableaux sont égaux.
IV-B. Assertion d'égalité pour les « double » avec un delta maximal entre les deux valeurs à comparer▲
La javadoc de cette assertion est disponible ici et ici.
Cette assertion est présente dans JUnit depuis la version 4.4. L'assertion d'égalité pour les doubles sans delta est passée en déprécié à partir de la version 4.5 de JUnit.
package
com.developpez.rpouiller.testsjunit4;
public
class
Operations {
public
static
double
soustraire
(
final
double
...pNombres) {
if
(
pNombres.length <
2
) {
throw
new
IllegalArgumentException
(
"Il faut au moins deux nombres en entrée"
);
}
double
lRetour =
pNombres[0
];
for
(
int
i=
1
;i<
pNombres.length;i++
) {
lRetour -=
pNombres[i];
}
return
lRetour;
}
}
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestDoubleAvecDelta {
@Test
public
void
valeursExactementEgales
(
) {
final
double
lResultat =
Operations.soustraire
(
5
, 2.5
);
Assert.assertEquals
(
2.5
, lResultat, 0
);
}
@Test
public
void
valeursAvecUneLegereDifference
(
) {
final
double
lResultat =
Operations.soustraire
(
71.19
, 98
);
Assert.assertEquals
(-
26.81
, lResultat, 0.005
);
}
@Test
public
void
valeursAvecUneDifferenceTropImportante
(
) {
final
double
lResultat =
Operations.soustraire
(
71.19
, 98
);
Assert.assertEquals
(-
26.81
, lResultat, 0
);
}
}
Comme le montre la capture d'écran ci-dessous, le paramètre delta permet de considérer que l'assertion est juste même s'il y a une différence entre les valeurs, tant que cette différence est inférieure au delta.
IV-C. Assertion sur une condition définie par contrat▲
La javadoc de cette assertion est disponible ici et ici.
Cette assertion est présente dans JUnit depuis la version 4.4.
Pour que l'assertion soit juste, il faut que le contrat soit vérifié.
IV-C-1. Contrat « pareil » : IsSame▲
La javadoc de ce contrat est disponible ici.
Le contrat vérifie que l'instance passée en premier paramètre de l'assertion et celle passée en paramètre du contrat sont les mêmes.
package
com.developpez.rpouiller.testsjunit4;
import
org.hamcrest.core.IsSame;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestContratPareil {
@Test
public
void
pareil
(
) {
// Remarque : c'est la même instance à cause du cache
Assert.assertThat
(
"texte"
, IsSame.sameInstance
(
"texte"
));
}
@Test
public
void
pasPareil
(
) {
// Remarque : ce n'est pas la même instance parce que new String() force une nouvelle instance.
Assert.assertThat
(
new
String
(
"texte"
), IsSame.sameInstance
(
"texte"
));
}
}
Comme le montre la capture d'écran ci-dessous, l'assertion échoue si les instances ne sont pas les mêmes.
IV-C-2. Contrat « égalité » : IsEqual▲
La javadoc de ce contrat est disponible ici.
Le contrat vérifie que l'instance passée en premier paramètre de l'assertion et celle passée en paramètre du contrat sont égales.
package
com.developpez.rpouiller.testsjunit4;
import
org.hamcrest.core.IsEqual;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestContratEgal {
@Test
public
void
egal1
(
) {
Assert.assertThat
(
"texte"
, IsEqual.equalTo
(
"texte"
));
}
@Test
public
void
egal2
(
) {
Assert.assertThat
(
new
String
(
"texte"
), IsEqual.equalTo
(
"texte"
));
}
@Test
public
void
pasEgal1
(
) {
Assert.assertThat
(
"Texte"
, IsEqual.equalTo
(
"texte"
));
}
@Test
public
void
pasEgal2
(
) {
Assert.assertThat
(
new
String
(
"Texte"
), IsEqual.equalTo
(
"texte"
));
}
}
Comme le montre la capture d'écran ci-dessous, l'assertion échoue si les instances ne sont pas égales.
IV-C-3. Contrat « classe de l'instance » : IsInstanceOf▲
La javadoc de ce contrat est disponible ici.
Le contrat vérifie que l'instance passée en premier paramètre de l'assertion est de la classe passée en paramètre du contrat.
package
com.developpez.rpouiller.testsjunit4;
import
java.io.Serializable;
import
org.hamcrest.core.IsInstanceOf;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestContratClasseInstance {
@Test
public
void
classeDeString
(
) {
Assert.assertThat
(
"texte"
, IsInstanceOf.instanceOf
(
String.class
));
}
@Test
public
void
classeDeSerializable
(
) {
Assert.assertThat
(
"texte"
, IsInstanceOf.instanceOf
(
Serializable.class
));
}
@Test
public
void
classeDeCharSequence
(
) {
Assert.assertThat
(
"texte"
, IsInstanceOf.instanceOf
(
CharSequence.class
));
}
@Test
public
void
classeDeInteger
(
) {
Assert.assertThat
(
"texte"
, IsInstanceOf.instanceOf
(
Integer.class
));
}
}
Comme le montre la capture d'écran ci-dessous, l'assertion échoue si l'instance n'est pas de la bonne classe.
IV-C-4. Contrat « valeur null » : IsNull▲
La javadoc de ce contrat est disponible ici.
Le contrat vérifie que la référence passée en premier paramètre de l'assertion est null ou n'est pas null.
package
com.developpez.rpouiller.testsjunit4;
import
org.hamcrest.core.IsNull;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestContratValeurNull {
@Test
public
void
valeurNull1
(
) {
final
String lTexte =
null
;
Assert.assertThat
(
lTexte, IsNull.nullValue
(
));
}
@Test
public
void
valeurNull2
(
) {
final
String lTexte =
"texte"
;
Assert.assertThat
(
lTexte, IsNull.nullValue
(
));
}
@Test
public
void
valeurPasNull1
(
) {
final
String lTexte =
null
;
Assert.assertThat
(
lTexte, IsNull.notNullValue
(
));
}
@Test
public
void
valeurPasNull2
(
) {
final
String lTexte =
"texte"
;
Assert.assertThat
(
lTexte, IsNull.notNullValue
(
));
}
}
Comme le montre la capture d'écran ci-dessous, l'assertion échoue si la référence ne correspond pas au contrat.
IV-C-5. Contrat « être » : Is▲
La javadoc de ce contrat est disponible ici.
Le contrat vérifie que l'instance passée en premier paramètre correspond à ce qui est passé (classe, valeur, autre contrat) en paramètre du contrat. Ce contrat n'apporte pas de nouveau type de contrats :
- si on passe une classe, cela correspond à un contrat « classe de l'instance » ;
- si on passe une valeur, cela correspond à un contrat « égalité » ;
- si on passe un autre contrat, cela correspond à cet autre contrat.
package
com.developpez.rpouiller.testsjunit4;
import
org.hamcrest.core.Is;
import
org.hamcrest.core.IsSame;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestContratEtre {
@Test
public
void
classeDeString
(
) {
Assert.assertThat
(
"texte"
, Is.is
(
String.class
));
}
@Test
public
void
classeDeInteger
(
) {
Assert.assertThat
(
"texte"
, Is.is
(
Integer.class
));
}
@Test
public
void
egal
(
) {
Assert.assertThat
(
"texte"
, Is.is
(
"texte"
));
}
@Test
public
void
pasEgal
(
) {
Assert.assertThat
(
"Texte"
, Is.is
(
"texte"
));
}
@Test
public
void
pareil
(
) {
Assert.assertThat
(
"texte"
, Is.is
(
IsSame.sameInstance
(
"texte"
)));
}
@Test
public
void
pasPareil
(
) {
Assert.assertThat
(
new
String
(
"texte"
), Is.is
(
IsSame.sameInstance
(
"texte"
)));
}
}
Comme le montre la capture d'écran ci-dessous, l'assertion réussit si l'instance est de la classe passée en paramètre du contrat, si elle est égale à la valeur passée en paramètre du contrat ou si le contrat passé en paramètre du contrat « être » est respecté.
IV-C-6. Contrat « ne pas être » : IsNot▲
La javadoc de ce contrat est disponible ici.
Le contrat vérifie que l'instance passée en premier paramètre ne correspond pas à ce qui est passé (valeur ou autre contrat) en paramètre du contrat. Ce contrat n'apporte pas de nouveau type de contrats :
- si on passe une valeur, cela correspond à un contrat « égalité » ;
- si on passe un autre contrat, cela correspond à cet autre contrat.
package
com.developpez.rpouiller.testsjunit4;
import
org.hamcrest.core.IsNot;
import
org.hamcrest.core.IsSame;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestContratNePasEtre {
@Test
public
void
egal
(
) {
Assert.assertThat
(
"texte"
, IsNot.not
(
"texte"
));
}
@Test
public
void
pasEgal
(
) {
Assert.assertThat
(
"Texte"
, IsNot.not
(
"texte"
));
}
@Test
public
void
pareil
(
) {
Assert.assertThat
(
"texte"
, IsNot.not
(
IsSame.sameInstance
(
"texte"
)));
}
@Test
public
void
pasPareil
(
) {
Assert.assertThat
(
new
String
(
"texte"
), IsNot.not
(
IsSame.sameInstance
(
"texte"
)));
}
}
Comme le montre la capture d'écran ci-dessous, l'assertion réussit si l'instance n'est pas égale à la valeur passée en paramètre du contrat ou si le contrat passé en paramètre du contrat « ne pas être » n'est pas respecté.
IV-C-7. Contrat « tous » : AllOf▲
La javadoc de ce contrat est disponible ici.
Le contrat vérifie que tous les contrats passés en paramètre du contrat sont respectés.
package
com.developpez.rpouiller.testsjunit4;
import
org.hamcrest.core.AllOf;
import
org.hamcrest.core.IsEqual;
import
org.hamcrest.core.IsInstanceOf;
import
org.hamcrest.core.IsNot;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestContratTous {
@Test
public
void
classeDeStringEtEgal
(
) {
Assert.assertThat
(
"texte"
, AllOf.allOf
(
IsInstanceOf.instanceOf
(
String.class
), IsEqual.equalTo
(
"texte"
)
));
}
@Test
public
void
classeDeIntegerEtEgal
(
) {
Assert.assertThat
(
"texte"
, AllOf.allOf
(
IsInstanceOf.instanceOf
(
Integer.class
), IsEqual.equalTo
(
"texte"
)
));
}
@Test
public
void
classeDeStringEtPasEgal
(
) {
Assert.assertThat
(
"texte"
, AllOf.allOf
(
IsInstanceOf.instanceOf
(
String.class
), IsEqual.equalTo
(
"Texte"
)
));
}
@Test
public
void
classeDeIntegerEtPasEgal
(
) {
Assert.assertThat
(
"texte"
, AllOf.allOf
(
IsInstanceOf.instanceOf
(
Integer.class
), IsEqual.equalTo
(
"Texte"
)
));
}
@Test
public
void
classeDePasIntegerEtEgal
(
) {
Assert.assertThat
(
"texte"
, AllOf.allOf
(
IsNot.not
(
IsInstanceOf.instanceOf
(
Integer.class
)), IsEqual.equalTo
(
"texte"
)
));
}
@Test
public
void
classeDeStringEtPasPasEgal
(
) {
Assert.assertThat
(
"texte"
, AllOf.allOf
(
IsInstanceOf.instanceOf
(
String.class
), IsNot.not
(
IsEqual.equalTo
(
"Texte"
))
));
}
}
Comme le montre la capture d'écran ci-dessous, les assertions où les deux sous-contrats sont respectés réussissent.
IV-C-8. Contrat « au moins un » : AnyOf▲
La javadoc de ce contrat est disponible ici.
Le contrat vérifie qu'au moins un des contrats passés en paramètre du contrat est respecté.
package
com.developpez.rpouiller.testsjunit4;
import
org.hamcrest.core.AnyOf;
import
org.hamcrest.core.IsEqual;
import
org.hamcrest.core.IsInstanceOf;
import
org.junit.Assert;
import
org.junit.Test;
public
class
TestContratAuMoinsUn {
@Test
public
void
classeDeStringEtEgal
(
) {
Assert.assertThat
(
"texte"
, AnyOf.anyOf
(
IsInstanceOf.instanceOf
(
String.class
), IsEqual.equalTo
(
"texte"
)
));
}
@Test
public
void
classeDeIntegerEtEgal
(
) {
Assert.assertThat
(
"texte"
, AnyOf.anyOf
(
IsInstanceOf.instanceOf
(
Integer.class
), IsEqual.equalTo
(
"texte"
)
));
}
@Test
public
void
classeDeStringEtPasEgal
(
) {
Assert.assertThat
(
"texte"
, AnyOf.anyOf
(
IsInstanceOf.instanceOf
(
String.class
), IsEqual.equalTo
(
"Texte"
)
));
}
@Test
public
void
classeDeIntegerEtPasEgal
(
) {
Assert.assertThat
(
"texte"
, AnyOf.anyOf
(
IsInstanceOf.instanceOf
(
Integer.class
), IsEqual.equalTo
(
"Texte"
)
));
}
}
Comme le montre la capture d'écran ci-dessous, les assertions où au moins un sous-contrat est respecté réussissent.
IV-C-9. Pour aller plus loin : les contrats hors JUnit▲
Les assertions par contrat sont désormais intégrées à JUnit, mais sont à l'origine développées par JMock.
La librairie originale comprend des contrats supplémentaires. La javadoc de JMock est disponible ici.
Ces contrats sont séparés en 7 groupes :
- core (contrats intégrés dans JUnit et déjà vus dans les chapitres précédents) : contrats de base sur les objets et les valeurs, ainsi que les contrats composés ;
- beans : contrats sur les beans Java et leurs valeurs ;
- collection : contrats sur les tableaux et les collections ;
- number : contrats de comparaison numérique ;
- object : contrats de contrôle des objets et des classes ;
- text : contrats de comparaison de textes ;
- xml : contrats sur les documents XML.
Pour pouvoir les utiliser, il faut rajouter les jar : « jmock-2.5.1.jar », « hamcrest-core-1.1.jar » et « hamcrest-library-1.1.jar ».
IV-C-9-a. Les contrats beans▲
Le contrat « HasProperty » vérifie qu'un bean possède bien les getter et setter correspondants à une propriété. La javadoc de ce contrat est disponible ici.
Le contrat « HasPropertyWithValue » vérifie que la valeur d'une propriété d'un bean respecte un contrat passé en paramètre. La javadoc de ce contrat est disponible ici.
package
com.developpez.rpouiller.testsjunit4;
public
class
BeanSansPropriete {
}
package
com.developpez.rpouiller.testsjunit4;
public
class
BeanAvecPropriete {
private
Integer prop;
public
void
setProp
(
Integer pProp){
prop =
pProp;}
public
Integer getProp
(
){
return
prop;}
}
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.equalTo;
import
static
org.hamcrest.Matchers.hasProperty;
import
static
org.junit.Assert.assertThat;
import
org.junit.Test;
public
class
TestContratBean {
@Test
public
void
beanSansPropriete
(
) {
assertThat
(
new
BeanSansPropriete
(
), hasProperty
(
"prop"
));
}
@Test
public
void
beanAvecPropriete
(
) {
assertThat
(
new
BeanAvecPropriete
(
), hasProperty
(
"prop"
));
}
@Test
public
void
beanAvecBonneValeur
(
) {
final
BeanAvecPropriete lBean =
new
BeanAvecPropriete
(
);
lBean.setProp
(
10
);
assertThat
(
lBean, hasProperty
(
"prop"
, equalTo
(
10
)));
}
@Test
public
void
beanAvecMauvaiseValeur
(
) {
final
BeanAvecPropriete lBean =
new
BeanAvecPropriete
(
);
assertThat
(
lBean, hasProperty
(
"prop"
, equalTo
(
10
)));
}
}
Comme le montre la capture d'écran ci-dessous, le contrat valide la présence d'une propriété et le respect d'un contrat par la valeur d'une propriété.
IV-C-9-b. Les contrats collection▲
Le contrat « IsArray » vérifie que les éléments d'un tableau respectent un tableau de contrats (un contrat par élément). La javadoc de ce contrat est disponible ici.
Le contrat « IsArrayContaining » vérifie qu'un tableau contient au moins un élément qui respecte un contrat passé en paramètre ou qui est égal à une valeur passée en paramètre. La javadoc de ce contrat est disponible ici.
Le contrat « IsCollectionContaining » vérifie qu'une Collection contient des éléments qui respectent un ou des contrats passés en paramètres ou qui sont égaux à une valeur ou des valeurs passées en paramètres. La javadoc de ce contrat est disponible ici.
Le contrat « IsIn » vérifie qu'un objet est contenu dans une Collection, un tableau ou parmi les paramètres du contrat. La javadoc de ce contrat est disponible ici.
Le contrat « IsMapContaining » vérifie qu'une Map contient une entrée, une clé ou valeur qui respecte un contrat ou qui est égale à une valeur passée en paramètre. La javadoc de ce contrat est disponible ici.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.junit.Assert.assertThat;
import
static
org.hamcrest.collection.IsArray.array;
import
static
org.hamcrest.Matchers.is;
import
org.junit.Test;
public
class
TestContratCollectionIsArray {
@Test
public
void
elementsEgaux
(
) {
assertThat
(
new
Integer[]{
1
, 2
}
, array
(
is
(
1
), is
(
2
)));
}
@Test
public
void
elementsDifferents
(
) {
assertThat
(
new
Integer[]{
1
, 2
}
, array
(
is
(
1
), is
(
3
)));
}
}
Comme le montre la capture d'écran ci-dessous, le contrat valide le respect par chaque élément du tableau d'un contrat.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.junit.Assert.assertThat;
import
static
org.hamcrest.Matchers.hasItemInArray;
import
static
org.hamcrest.Matchers.nullValue;
import
org.junit.Test;
public
class
TestContratCollectionIsArrayContaining {
@Test
public
void
contientElementContrat
(
) {
assertThat
(
new
Long[]{
1
L, null
}
, hasItemInArray
(
nullValue
(
)));
}
@Test
public
void
neContientPasElementContrat
(
) {
assertThat
(
new
Long[]{
1
L, 2
L}
, hasItemInArray
(
nullValue
(
)));
}
@Test
public
void
contientElement
(
) {
assertThat
(
new
Long[]{
1
L, 2
L}
, hasItemInArray
(
1
L));
}
@Test
public
void
neContientPasElement
(
) {
assertThat
(
new
Long[]{
1
L, 2
L}
, hasItemInArray
(
3
L));
}
}
Comme le montre la capture d'écran ci-dessous, le contrat valide que le tableau possède au moins un élément avec la valeur ou respectant le contrat passé en paramètre.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.hasItem;
import
static
org.hamcrest.Matchers.hasItems;
import
static
org.hamcrest.Matchers.is;
import
static
org.junit.Assert.assertThat;
import
java.util.Arrays;
import
org.junit.Test;
public
class
TestContratCollectionIsCollectionContaining {
@Test
public
void
contientElementContrat
(
) {
assertThat
(
Arrays.asList
(
1
L, 2
L), hasItem
(
is
(
1
L)));
}
@Test
public
void
neContientPasElementContrat
(
) {
assertThat
(
Arrays.asList
(
3
L, 2
L), hasItem
(
is
(
1
L)));
}
@Test
public
void
contientElementsContrat
(
) {
assertThat
(
Arrays.asList
(
1
L, 2
L), hasItems
(
is
(
1
L), is
(
2
L)));
}
@Test
public
void
neContientPasElementsContrat
(
) {
assertThat
(
Arrays.asList
(
1
L, null
), hasItems
(
is
(
1
L), is
(
2
L)));
}
@Test
public
void
contientElement
(
) {
assertThat
(
Arrays.asList
(
1
L, 2
L), hasItem
(
1
L));
}
@Test
public
void
neContientPasElement
(
) {
assertThat
(
Arrays.asList
(
1
L, 2
L), hasItem
(
3
L));
}
@Test
public
void
contientElements
(
) {
assertThat
(
Arrays.asList
(
1
L, 2
L), hasItems
(
1
L, 2
L));
}
@Test
public
void
neContientPasElements
(
) {
assertThat
(
Arrays.asList
(
1
L, 2
L), hasItems
(
1
L, 2
L, 3
L));
}
}
Comme le montre la capture d'écran ci-dessous, les contrats valident que la collection possède au moins un élément ou des éléments avec la/les valeur(s) ou respectant le(s) contrat(s) passé(s) en paramètre(s).
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.isIn;
import
static
org.hamcrest.Matchers.isOneOf;
import
static
org.junit.Assert.assertThat;
import
java.util.Arrays;
import
org.junit.Test;
public
class
TestContratCollectionIsIn {
@Test
public
void
presentDansCollection
(
) {
assertThat
(
"a"
, isIn
(
Arrays.asList
(
"a"
, "z"
, "e"
, "r"
, "t"
, "y"
)));
}
@Test
public
void
absentDeCollection
(
) {
assertThat
(
"A"
, isIn
(
Arrays.asList
(
"a"
, "z"
, "e"
, "r"
, "t"
, "y"
)));
}
@Test
public
void
presentDansTableau
(
) {
assertThat
(
"a"
, isIn
(
new
String[]{
"a"
, "z"
, "e"
, "r"
, "t"
, "y"
}
));
}
@Test
public
void
absentDeTableau
(
) {
assertThat
(
"A"
, isIn
(
new
String[]{
"a"
, "z"
, "e"
, "r"
, "t"
, "y"
}
));
}
@Test
public
void
present
(
) {
assertThat
(
"a"
, isOneOf
(
"a"
, "z"
, "e"
, "r"
, "t"
, "y"
));
}
@Test
public
void
absent
(
) {
assertThat
(
"A"
, isOneOf
(
"a"
, "z"
, "e"
, "r"
, "t"
, "y"
));
}
}
Comme le montre la capture d'écran ci-dessous, les contrats valident que la valeur appartient à un ensemble.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.hasEntry;
import
static
org.hamcrest.Matchers.is;
import
static
org.hamcrest.Matchers.not;
import
static
org.junit.Assert.assertThat;
import
java.util.HashMap;
import
java.util.Map;
import
org.hamcrest.collection.IsMapContaining;
import
org.junit.Before;
import
org.junit.Test;
public
class
TestContratCollectionIsMapContaining {
private
Map<
String, Long>
hashMap;
@Before
public
void
initialise
(
) {
hashMap =
new
HashMap<
String, Long>(
);
hashMap.put
(
"cle1"
, 1
L);
hashMap.put
(
"cle2"
, 2
L);
}
@Test
public
void
contientEntree
(
) {
assertThat
(
hashMap, hasEntry
(
"cle1"
, 1
L));
}
@Test
public
void
neContientPasEntree
(
) {
assertThat
(
hashMap, hasEntry
(
"cle1"
, 2
L));
}
@Test
public
void
contientEntreeContrat
(
) {
assertThat
(
hashMap, hasEntry
(
is
(
"cle1"
), not
(
2
L)));
}
@Test
public
void
neContientPasEntreeContrat
(
) {
assertThat
(
hashMap, hasEntry
(
is
(
"cle1"
), not
(
1
L)));
}
@Test
public
void
contientCle
(
) {
assertThat
(
hashMap, IsMapContaining.<
String, Long>
hasKey
(
"cle1"
));
}
@Test
public
void
neContientPasCleEntree
(
) {
assertThat
(
hashMap, IsMapContaining.<
String, Long>
hasKey
(
"cle3"
));
}
@Test
public
void
contientCleContrat
(
) {
assertThat
(
hashMap, IsMapContaining.<
String, Long>
hasKey
(
is
(
"cle1"
)));
}
@Test
public
void
neContientPasCleContrat
(
) {
assertThat
(
hashMap, IsMapContaining.<
String, Long>
hasKey
(
is
(
"cle3"
)));
}
@Test
public
void
contientValeur
(
) {
assertThat
(
hashMap, IsMapContaining.<
String, Long>
hasValue
(
1
L));
}
@Test
public
void
neContientPasValeur
(
) {
assertThat
(
hashMap, IsMapContaining.<
String, Long>
hasValue
(
3
L));
}
@Test
public
void
contientValeurContrat
(
) {
assertThat
(
hashMap, IsMapContaining.<
String, Long>
hasValue
(
is
(
1
L)));
}
@Test
public
void
neContientPasValeurContrat
(
) {
assertThat
(
hashMap, IsMapContaining.<
String, Long>
hasValue
(
is
(
3
L)));
}
}
Comme le montre la capture d'écran ci-dessous, les contrats valident qu'un objet Map possède une entrée, une clé ou une valeur ou respectant un contrat passé en paramètre.
IV-C-9-c. Les contrats number▲
Le contrat « IsCloseTo » vérifie qu'un nombre passé en paramètre est suffisamment proche d'un autre nombre. La javadoc de ce contrat est disponible ici.
Le contrat « OrderingComparisons » vérifie qu'un nombre passé en paramètre est supérieur, supérieur ou égal, inférieur, inférieur ou égal à une autre valeur. La javadoc de ce contrat est disponible ici.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.closeTo;
import
static
org.hamcrest.Matchers.greaterThan;
import
static
org.hamcrest.Matchers.greaterThanOrEqualTo;
import
static
org.hamcrest.Matchers.lessThan;
import
static
org.hamcrest.Matchers.lessThanOrEqualTo;
import
static
org.junit.Assert.assertThat;
import
org.junit.Test;
public
class
TestContratNumber {
@Test
public
void
proche
(
) {
assertThat
(
20.5
, closeTo
(
20
, 0.5
));
}
@Test
public
void
pasProche
(
) {
assertThat
(
20.5
, closeTo
(
20
, 0.1
));
}
@Test
public
void
plusGrand
(
) {
assertThat
(
21
, greaterThan
(
20
));
}
@Test
public
void
pasPlusGrand
(
) {
assertThat
(
20
, greaterThan
(
20
));
}
@Test
public
void
plusGrandOuEgal
(
) {
assertThat
(
20
, greaterThanOrEqualTo
(
20
));
}
@Test
public
void
pasPlusGrandOuEgal
(
) {
assertThat
(
19
, greaterThanOrEqualTo
(
20
));
}
@Test
public
void
plusPetit
(
) {
assertThat
(
19
, lessThan
(
20
));
}
@Test
public
void
pasPlusPetit
(
) {
assertThat
(
20
, lessThan
(
20
));
}
@Test
public
void
plusPetitOuEgal
(
) {
assertThat
(
20
, lessThanOrEqualTo
(
20
));
}
@Test
public
void
pasPlusPetitOuEgal
(
) {
assertThat
(
21
, lessThanOrEqualTo
(
20
));
}
}
Comme le montre la capture d'écran ci-dessous, les contrats valident la comparaison entre les deux nombres.
IV-C-9-d. Les contrats object▲
Le contrat « HasToString » vérifie que la valeur retournée par le toString() de l'objet passé en paramètre respecte un contrat. La javadoc de ce contrat est disponible ici.
Le contrat « IsCompatibleType » vérifie que la classe passée en paramètre est compatible avec celle passée en paramètre du contrat. La javadoc de ce contrat est disponible ici.
Le contrat « IsEventFrom » vérifie l'origine (et la classe) d'un évènement. La javadoc de ce contrat est disponible ici.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.hasToString;
import
static
org.hamcrest.Matchers.is;
import
static
org.hamcrest.Matchers.typeCompatibleWith;
import
static
org.junit.Assert.assertThat;
import
org.junit.Test;
public
class
TestContratObject {
@Test
public
void
toStringOK
(
) {
assertThat
(
new
Long
(
30
), hasToString
(
is
(
"30"
)));
}
@Test
public
void
toStringNOK
(
) {
assertThat
(
new
Long
(
30
), hasToString
(
is
(
" 30"
)));
}
@Test
public
void
compatible
(
) {
assertThat
(
Long.class
, typeCompatibleWith
(
Number.class
));
}
@Test
public
void
incompatible
(
) {
assertThat
(
Long.class
, typeCompatibleWith
(
String.class
));
}
}
Comme le montre la capture d'écran ci-dessous, les contrats valident la valeur retournée par le toString() d'un objet et la compatibilité entre deux classes.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.eventFrom;
import
static
org.junit.Assert.assertThat;
import
java.beans.PropertyChangeEvent;
import
javax.swing.event.ChangeEvent;
import
org.junit.Before;
import
org.junit.Test;
public
class
TestContratObjectIsEventFrom {
private
Object source;
private
ChangeEvent event;
@Before
public
void
initialise
(
) {
source =
"source"
;
event =
new
ChangeEvent
(
source);
}
@Test
public
void
envementOrigine
(
) {
assertThat
(
event, eventFrom
(
source));
}
@Test
public
void
envenementAutreOrigine
(
) {
assertThat
(
event, eventFrom
(
"autreSource"
));
}
@Test
public
void
evenementClasse
(
) {
assertThat
(
event, eventFrom
(
ChangeEvent.class
, source));
}
@Test
public
void
evenementAutreClasse
(
) {
assertThat
(
event, eventFrom
(
PropertyChangeEvent.class
, source));
}
}
Comme le montre la capture d'écran ci-dessous, le contrat valide l'origine d'un évènement et sa classe.
IV-C-9-e. Les contrats text▲
Le contrat « IsEqualIgnoringCase » vérifie l'égalité de deux chaines de caractères sans tenir compte de la casse. La javadoc de ce contrat est disponible ici.
Le contrat « IsEqualIgnoringWhiteSpace » vérifie l'égalité de deux chaines de caractères sans tenir compte des espaces. La javadoc de ce contrat est disponible ici.
Le contrat « StringContains » vérifie que la chaine de caractères passée en paramètre contient la chaine de caractère passée en paramètre du contrat. La javadoc de ce contrat est disponible ici.
Le contrat « StringEndsWith » vérifie que la chaine de caractère passée en paramètre finit par la chaine de caractère passée en paramètre du contrat. La javadoc de ce contrat est disponible ici.
Le contrat « StringStartsWith » vérifie que la chaine de caractère passée en paramètre commence par la chaine de caractères passée en paramètre du contrat. La javadoc de ce contrat est disponible ici.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.containsString;
import
static
org.hamcrest.Matchers.endsWith;
import
static
org.hamcrest.Matchers.equalToIgnoringCase;
import
static
org.hamcrest.Matchers.equalToIgnoringWhiteSpace;
import
static
org.hamcrest.Matchers.startsWith;
import
static
org.junit.Assert.assertThat;
import
org.junit.Test;
public
class
TestContratText {
@Test
public
void
egalCasse
(
) {
assertThat
(
"azerty"
, equalToIgnoringCase
(
"Azerty"
));
}
@Test
public
void
pasEgalCasse
(
) {
assertThat
(
"azerty"
, equalToIgnoringCase
(
"Qwerty"
));
}
@Test
public
void
egalEspace
(
) {
assertThat
(
"a
\n
z e r t y"
, equalToIgnoringWhiteSpace
(
"a z e r
\n
t y"
));
}
@Test
public
void
pasEgalEspace
(
) {
assertThat
(
"a z e r t y"
, equalToIgnoringWhiteSpace
(
"q w e r t y"
));
}
@Test
public
void
contient
(
) {
assertThat
(
"azerty"
, containsString
(
"zert"
));
}
@Test
public
void
neContientPas
(
) {
assertThat
(
"azerty"
, containsString
(
"wert"
));
}
@Test
public
void
commencePar
(
) {
assertThat
(
"azerty"
, startsWith
(
"azer"
));
}
@Test
public
void
neCommencePasPar
(
) {
assertThat
(
"azerty"
, startsWith
(
"qwer"
));
}
@Test
public
void
finitPar
(
) {
assertThat
(
"azerty"
, endsWith
(
"erty"
));
}
@Test
public
void
neFinitPasPar
(
) {
assertThat
(
"azerty"
, endsWith
(
"erti"
));
}
}
Comme le montre la capture d'écran ci-dessous, les contrats valident les relations entre les deux chaines de caractères.
IV-C-9-f. Les contrats XML▲
Le contrat « HasXPath » vérifie qu'un chemin existe et/ou respecte un contrat dans un document XML. La javadoc de ce contrat est disponible ici.
package
com.developpez.rpouiller.testsjunit4;
import
static
org.hamcrest.Matchers.equalToIgnoringCase;
import
static
org.hamcrest.Matchers.hasXPath;
import
static
org.junit.Assert.assertThat;
import
javax.xml.parsers.DocumentBuilder;
import
javax.xml.parsers.DocumentBuilderFactory;
import
javax.xml.parsers.ParserConfigurationException;
import
org.junit.Before;
import
org.junit.Test;
import
org.w3c.dom.Document;
import
org.w3c.dom.Element;
public
class
TestContratXML {
private
Document document;
@Before
public
void
initialise
(
) throws
ParserConfigurationException {
final
DocumentBuilderFactory lDocumentBuilderFactory =
DocumentBuilderFactory.newInstance
(
);
final
DocumentBuilder lDocumentBuilder =
lDocumentBuilderFactory.newDocumentBuilder
(
);
document =
lDocumentBuilder.newDocument
(
);
final
Element lElement =
document.createElement
(
"racine"
);
document.appendChild
(
lElement);
final
Element lElement1 =
document.createElement
(
"element1"
);
lElement1.appendChild
(
document.createTextNode
(
"texteElement1"
));
lElement.appendChild
(
lElement1);
final
Element lElement2 =
document.createElement
(
"element2"
);
lElement2.appendChild
(
document.createTextNode
(
"texteElement2"
));
lElement.appendChild
(
lElement2);
}
@Test
public
void
avecChemin
(
) {
assertThat
(
document, hasXPath
(
"/racine/element1"
));
}
@Test
public
void
sansChemin
(
) {
assertThat
(
document, hasXPath
(
"/racine/element3"
));
}
@Test
public
void
avecCheminContrat
(
) {
assertThat
(
document, hasXPath
(
"/racine/element1"
, equalToIgnoringCase
(
"texteelement1"
)));
}
@Test
public
void
sansCheminContrat
(
) {
assertThat
(
document, hasXPath
(
"/racine/element1"
, equalToIgnoringCase
(
"texteelement2"
)));
}
}
Comme le montre la capture d'écran ci-dessous, le contrat valide que le document XML possède un chemin et que ce chemin respecte un contrat.
V. LES SUPPOSITIONS▲
La javadoc des suppositions est disponible ici.
Les suppositions sont présentes dans JUnit depuis la version 4.4.
Une supposition vérifie une condition. Si la condition n'est pas vérifiée, le test s'arrête, mais ne passe pas en erreur ou en échec.
Les différentes suppositions sont :
- assumeNoException(java.lang.Throwable) : vérifie qu'une opération s'est déroulée sans lever de Throwable ;
- assumeNotNull(java.lang.Object…) : vérifie qu'aucun des paramètres n'est à null ;
- assumeThat(T, org.hamcrest.Matcher) : vérifie qu'une condition définie par contrat est respectée (voir « Assertion sur une condition définie par contrat ») ;
- assumeTrue(boolean) : vérifie que le paramètre est vrai.
package
com.developpez.rpouiller.testsjunit4;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.IOException;
import
org.junit.Assert;
import
org.junit.Assume;
import
org.junit.Test;
public
class
TestSupposition {
@Test
public
void
verifierExistenceFichier
(
) {
final
File lFile =
new
File
(
"fichier.txt"
);
Assert.assertTrue
(
"Le fichier doit exister"
, lFile.exists
(
));
}
@Test
public
void
lireFichier
(
) throws
IOException {
final
File lFile =
new
File
(
"fichier.txt"
);
Assume.assumeTrue
(
lFile.exists
(
));
final
FileInputStream lFileInputStream =
new
FileInputStream
(
lFile);
final
byte
[] lBytes =
new
byte
[16
];
lFileInputStream.read
(
lBytes);
Assert.assertArrayEquals
(
"Bonjour le monde"
.getBytes
(
), lBytes);
}
}
Comme le montre la capture d'écran ci-dessous, si le fichier n'existe pas, seul le test vérifiant la présence du fichier passe en échec.
VI. LES TESTS PARAMÉTRÉS▲
La javadoc des tests paramétrés est disponible ici.
Les tests paramétrés permettent d'exécuter plusieurs fois un cas de tests avec des valeurs différentes. Le cas de test doit être annoté avec @RunWith avec pour valeur Parameterized. Les paramètres sont indiqués par une méthode annotée avec @Parameters retournant une Collection. Le cas de tests paramétrés doit comporter un constructeur correspondant aux paramètres. Les tests paramétrés sont apparus avec la version 4.0 de JUnit.
package
com.developpez.rpouiller.testsjunit4;
public
class
Operations {
public
static
long
additionner
(
final
long
...pNombres) {
long
lRetour =
0
;
for
(
final
long
lNombre : pNombres) {
lRetour +=
lNombre;
}
return
lRetour;
}
// Cette méthode ne fonctionne pas correctement
// Les tests vont le vérifier
public
static
long
multiplier
(
final
long
...pNombres) {
long
lRetour =
0
;
for
(
final
long
lNombre : pNombres) {
lRetour *=
lNombre;
}
return
lRetour;
}
}
package
com.developpez.rpouiller.testsjunit4;
import
java.util.Arrays;
import
java.util.List;
import
org.junit.Assert;
import
org.junit.Test;
import
org.junit.runner.RunWith;
import
org.junit.runners.Parameterized;
import
org.junit.runners.Parameterized.Parameters;
@RunWith
(
Parameterized.class
)
public
class
TestParametre {
@Parameters
public
static
List<
Object[]>
getParametres
(
) {
return
Arrays.asList
(
new
Object[][] {
{
10
L, 0
L, new
long
[] {
10
L, 0
L }
}
,
{
30
L, 300
L, new
long
[] {
10
L, 20
L }
}
,
{
7936
L, 1125899906842624
L, new
long
[] {
256
L, 512
L, 1024
L, 2048
L, 4096
L }
}
,
}
);
}
private
long
resultatAddition;
private
long
resultatMultiplication;
private
long
[] nombres;
public
TestParametre
(
long
pResultatAddition, long
pResultatMultiplication, long
[] pNombres) {
resultatAddition =
pResultatAddition;
resultatMultiplication =
pResultatMultiplication;
nombres =
pNombres;
}
@Test
public
void
addition
(
) {
System.out.println
(
"addition : - attendu : "
+
resultatAddition +
"
\n
- nombres : "
+
Arrays.toString
(
nombres));
final
long
lAddition =
Operations.additionner
(
nombres);
Assert.assertEquals
(
resultatAddition, lAddition);
}
@Test
public
void
mutiplication
(
) {
System.out.println
(
"mutiplication : - attendu : "
+
resultatMultiplication +
"
\n
- nombres : "
+
Arrays.toString
(
nombres));
final
long
lMultiplication =
Operations.multiplier
(
nombres);
Assert.assertEquals
(
resultatMultiplication, lMultiplication);
}
}
Comme le montre la capture d'écran et la trace ci-dessous, le cas de tests est exécuté plusieurs fois avec des paramètres différents.
mutiplication : - attendu : 0
- nombres : [10, 0]
addition : - attendu : 10
- nombres : [10, 0]
mutiplication : - attendu : 300
- nombres : [10, 20]
addition : - attendu : 30
- nombres : [10, 20]
mutiplication : - attendu : 1125899906842624
- nombres : [256, 512, 1024, 2048, 4096]
addition : - attendu : 7936
- nombres : [256, 512, 1024, 2048, 4096]
VII. LES ANNOTATIONS POUR LES SUITES DE TESTS▲
La javadoc de l'annotation des suites de tests est disponible ici.
Les suites des tests permettent d'exécuter plusieurs cas de tests dans la même exécution. La classe de suite doit être annotée avec @RunWith avec pour valeur Suite. Les cas de tests composants la suite sont indiqués par l'annotation @SuiteClasses.
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.Test;
public
class
TestSuitePartie1 {
@Test
public
void
test1
(
) {
}
}
package
com.developpez.rpouiller.testsjunit4;
import
static
org.junit.Assert.fail;
import
org.junit.Test;
public
class
TestSuitePartie2 {
@Test
public
void
test2
(
) {
fail
(
);
}
}
package
com.developpez.rpouiller.testsjunit4;
import
org.junit.runner.RunWith;
import
org.junit.runners.Suite;
import
org.junit.runners.Suite.SuiteClasses;
@RunWith
(
Suite.class
)
@SuiteClasses
({
TestSuitePartie1.class
, TestSuitePartie2.class
}
)
public
class
TestSuite {
}
Comme le montre la capture d'écran, les différents cas de tests sont exécutés dans la même exécution.
VIII. REMERCIEMENTS▲
Je remercie sincèrement par ordre plus ou moins chronologique :
- www.developpez.com me permettant de publier cet article ;
- Nono40 pour ses outils ;
- Mikrob pour ses encouragements ;
- djo.mos pour ses suggestions pertinentes et ses encouragements ;
- romaintaz pour sa relecture orthographique rigoureuse et ses encouragements.