Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
Achref El Mouelhi
elmouelhi.achref@gmail.com
1 Introduction
2 Premier exemple
4 Pre/Post test
5 Mockito
6 JUnit et Maven
7 Autres annotations
8 Recouvrement du code
JUnit
JUnit ?
Framework open source pour Java créé par Kent Beck et Erich
Gamma
I c
H
Permettant d’automatiser les tests et de s’assurer que le
EL
programme répond toujours aux besoins
U
Basé sur les assertions qui vL MOsi les résultats de tests
érifient
r e f E attendus
correspondent aux résultats
h
Membrecde A
c
la famille XUnit (CPPUnit pour C++, CUnit pour C,
PHPUnit pour PHP...)
Objectif
Trouver un maximum de bugs pour les corriger
JUnit
JUnit
Étape
JUnit
I c
public class Calcul {
public int somme(int x, int y) { ELH
U
return x + y;
L MO
}
f E
hre
public int division(int x, int y) {
c
if (y == 0)
c A
throw new ArithmeticException();
return x / y;
}
}
JUnit
Pour créer une classe de test
I
c
Saisir le nom CalculTest dans Name
EL H
Cocher les 4 cases de Which method stubsU
MO
would you like to
create ?
L
fdeEClass under test
Cliquer sur Browse en r
c h e
face
Chercherc
A
calcul, sélectionner Calcul - org.eclipse.main et valider
Cliquer sur Finish puis sur ok (pour valider Add JUnit 5 library to the
build path dans Perform the following action:)
Le code généré :
package org.eclipse.test;
import org.junit.jupiter.api.Test;
class CalculTest {
@BeforeAll
I c
static void setUpBeforeClass() throws Exception { }
ELH
@AfterAll
U
MO
static void tearDownAfterClass() throws Exception { }
@BeforeEach
void setUp() throws Exception {
f E L}
@AfterEach
chre
c A
void tearDown() throws Exception { }
@Test
void testSomme() {
fail("Not yet implemented");
}
@Test
void testDivision() {
fail("Not yet implemented");
}
}
JUnit
Nous parlerons de ces quatre méthodes dans une autre section
@BeforeAll
static void setUpBeforeClass() throws Exception {
}
I c
@AfterAll H
EL Exception {
U
}
L MO
static void tearDownAfterClass() throws
@BeforeEach chr
ef E
c Athrows Exception {
void setUp()
}
@AfterEach
void tearDown() throws Exception {
}
JUnit
Pour tester
I c
Faire un clic droit sur le la classe de test
Aller dans Run As > JUnit Test UE
LH
L MO
h r e fE
A c
c
JUnit
Pour tester
I c
Faire un clic droit sur le la classe de test
Aller dans Run As > JUnit Test UE
LH
L MO
h r e fE
A c
Résultat
c
2 Exécutions : 2 Échecs : car les deux méthodes de test sont vides
JUnit
Implémentons testSomme() en ciblant chaque fois les cas particuliers
void testSomme() {
Calcul calcul = new Calcul();
if (calcul.somme(2, 3) != 5)
fail("faux pour deux entiers positifs");
I c
if (calcul.somme(-2, -3) != -5)
ELH
fail("faux pour deux entiers négatifs");
U
if (calcul.somme(-2, 3) != 1)
L MO
E
fail("faux pour deux entiers de signe différent");
f
if (calcul.somme(0, 3) != 3)
chre
c A
fail("faux pour x nul");
if (calcul.somme(2, 0) != 2)
fail("faux pour y nul");
if (calcul.somme(0, 0) != 0)
fail("faux pour x et y nuls");
}
JUnit
Implémentons testSomme() en ciblant chaque fois les cas particuliers
void testSomme() {
Calcul calcul = new Calcul();
if (calcul.somme(2, 3) != 5)
fail("faux pour deux entiers positifs");
I c
if (calcul.somme(-2, -3) != -5)
ELH
fail("faux pour deux entiers négatifs");
U
if (calcul.somme(-2, 3) != 1)
L MO
E
fail("faux pour deux entiers de signe différent");
f
if (calcul.somme(0, 3) != 3)
chre
c A
fail("faux pour x nul");
if (calcul.somme(2, 0) != 2)
fail("faux pour y nul");
if (calcul.somme(0, 0) != 0)
fail("faux pour x et y nuls");
}
JUnit
c
assertNotNull(message, object) permet de vérifier, pour
les paramètres utilisés, qu’une méthode ne retourne pas la valeur
null (sa réciproque est assertNull)
...
JUnit
Remarques
I
c
H
EL d’erreur par
En l’absence d’un message explicite, un message
U
défaut sera affiché.
L MO
Les méthodes assertX()
h r e f Epeuvent aussi avoir la signature
A c
suivante : assertX(message, valeurAttendue,
c
appelDeMéthodeATester)
void testDivision() {
Calcul calcul = new Calcul();
assertFalse(calcul.division(6, 3) == 0, "2 entiers positifs");
assertEquals(2, calcul.division(-6, -3), "2 entiers négatifs");
assertNotNull(calcul.division(-6, 3), "2 entiers de signe diff");
assertTrue(calcul.division(0, 3) == 0, "entier x nul");
Throwable e = null;
I c
try {
calcul.division(2,0);
ELH
}
U
catch (Throwable ex) {
L MO
e = ex;
f E
hre
}
c
assertTrue(e instanceof ArithmeticException);
c A
e = null;
try {
calcul.division(0,0);
}
catch (Throwable ex) {
e = ex;
}
assertTrue(e instanceof ArithmeticException);
}
JUnit
JUnit
f E L
Après le test, il faut aussi fermer certaines ressources : connexion
chre
à une base de données, socket...
c A
JUnit
f E L
Après le test, il faut aussi fermer certaines ressources : connexion
chre
à une base de données, socket...
c A
Pour ces cas
On peut utiliser les méthodes setUp() et tearDown() qui sont
respectivement exécutées avant et après l’appel de chaque
méthode de test.
@BeforeAll
static void setUpBeforeClass() throws Exception {
System.out.println("BeforeAll");
}
@AfterAll
I c
static void tearDownAfterClass() throws Exception {
ELH
System.out.println("AfterAll");
U
}
L MO
f E
hre
@BeforeEach
c
void setUp() throws Exception {
} c A
System.out.println("BeforeEach");
@AfterEach
void tearDown() throws Exception {
System.out.println("AfterEach");
}
JUnit
I
c
@BeforeAll : la méthode annotée sera exécutée seulement
avant le premier test H
EécutLée seulement après
U
L MO
@AfterAll : la méthode annotée sera ex
ef E
le dernier test
@BeforeEachc: h la r
méthode annotée sera exécutée avant chaque
test
c A
@AfterEach : la méthode annotée sera exécutée après chaque
test
JUnit
I c
ELH
U
L MO
f E
chre
c A
JUnit
I c
ELH
U
Le résultat L MO
f E
BeforeAll
chre
BeforeEach
AfterEach
c A
BeforeEach
AfterEach
AfterAll
void testSomme() {
// le code précédent sans l’instanciation de calcul
}
@Test
void testDivision() {
// le code précédent sans l’instanciation de calcul
}
}
JUnit
Mock ?
Objet factice (fake object)
I c
permettant de reproduire le comportement d’un objet réel non
implémenté
ELH
U
L MO
f E
chre
c A
JUnit
Mock ?
Objet factice (fake object)
I c
permettant de reproduire le comportement d’un objet réel non
implémenté
ELH
U
L MO
f E
Mockito ? A c hre
c
Framework open source pour Java
Générateur automatique de doublures
Un seul type de Mock possible et une seule façon de le créer
JUnit
I c
Exemple, supposant qu’on
EL H
a une interface CalculService ayantU
M O une méthode carre()
f L
E sommeCarre() dans Calcul qui
veut développer une méthode
r e
utilise la méthodehcarre() de cette interface CalculService
c
c A
JUnit
L’interface CalculService
I c
package org.eclipse.main;
E LH
U
MO{
public interface CalculService
L
h r e
public int carre(intf Ex);
A c
}
c
JUnit
La classe Calcul
package org.eclipse.main;
// + le code précédent
JUnit
Pour tester la classe Calcul dans TestCalcul, il faut commencer par
instancier CalculService
class CalculTest {
Calcul calcul;
CalculService calculService;
I c
EL H
@BeforeEach
O U
L M
void setUp() throws Exception {
}
h r fE
calcul = new Calcul(calculService);
e
A c
@Test
c
void testSommeCarre() {
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul
exact");
}
// + le code precedent
JUnit
En testant, on aura l’erreur suivante
java.lang.NullPointerException
at org.eclipse.main.Calcul.sommeCarre(Calcul.java:6)
at org.eclipse.test.CalculTest.testSommeCarre(CalculTest.
java:26)
I c
ELH
U
L MO
f E
chre
c A
JUnit
En testant, on aura l’erreur suivante
java.lang.NullPointerException
at org.eclipse.main.Calcul.sommeCarre(Calcul.java:6)
at org.eclipse.test.CalculTest.testSommeCarre(CalculTest.
java:26)
I c
ELH
U
L MO
Explication
f E
chre
c A
La source de l’erreur est l’appel de la méthode carre(x) qui n’est pas
implémenté.
STUB (les bouchons en français) : classes qui renvoient en dur une valeur pour
une méthode invoquée
JUnit
Pour tester la classe Calcul dans TestCalcul, il faut
commencer par instancier CalculService
class CalculTest {
Calcul calcul;
I c
H
ELCalculService()
U
CalculService calculService = new
{
L MO
h r e fE
@Override
A ccarre(int x) {
//
c
public int
TODO Auto-generated method stub
return x * x;
}
};
// + le code précédent
JUnit
En testant
I c
tout se passe bien et le test est passé.
ELH
U
L MO
f E
chre
c A
JUnit
En testant
I c
tout se passe bien et le test est passé.
ELH
U
L MO
f E
c
On peut utiliser les mocks
A hre
c
pour cr
éer un objet factice de CalculService
JUnit
Démarche
Aller dans
I c
ELH
https://jar-download.com/artifacts/org.mockito et
U
MO
télécharger mockito-core
f E L
Créer un répertoire lib à la racine du projet
chre
c A
Décompresser l’archive mockito-core et copier les 4 .jar
dans lib
Ajouter les .jar de lib au path du projet
JUnit
Commençons par importer mockito dans la classe CalculTest
import static org.mockito.Mockito.*;
I c
ELH
U
L MO
f E
chre
c A
JUnit
Commençons par importer mockito dans la classe CalculTest
import static org.mockito.Mockito.*;
I
c
Remplaçons l’instanciation de CalculService par un mock
EL H
U
CalculService calculService = mock(CalculService.class);
L MO
h r e fE
A c
c
JUnit
Commençons par importer mockito dans la classe CalculTest
import static org.mockito.Mockito.*;
I
c
Remplaçons l’instanciation de CalculService par un mock
ELH
U
CalculService calculService = mock(CalculService.class);
L MO
r e E
f devient
c h
La méthode testSommeCarre() ainsi
@Test
c A
void testSommeCarre() {
when(calculService.carre(2)).thenReturn(4);
when(calculService.carre(3)).thenReturn(9);
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
JUnit
En testant
I c
ELH
U
L MO
f E
chre
c A
JUnit
En testant
I c
Pour vérifier que notre mock a bien été appelé
ELH
U
MO
on peut utiliser la méthode verify
f E L
chre
c A
JUnit
En testant
I c
Pour vérifier que notre mock a bien été appelé
ELH
U
MO
on peut utiliser la méthode verify
f E L
c h reà testSommeCarre()
c A
Ajoutons la méthode verify
@Test
void testSommeCarre() {
when(calculService.carre(2)).thenReturn(4);
when(calculService.carre(3)).thenReturn(9);
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
verify(calculService).carre(2);
}
JUnit
JUnit
JUnit
Le résultat est
Wanted but not invoked:
calculService.carre(2);
I c
-> at org.eclipse.test.CalculTest.testSommeCarre(
ELH
CalculTest.java:39)
U
MO
Actually, there were zero interactions with this mock.
L
f E
chre
c A
JUnit
Le résultat est
Wanted but not invoked:
calculService.carre(2);
I c
-> at org.eclipse.test.CalculTest.testSommeCarre(
ELH
CalculTest.java:39)
U
MO
Actually, there were zero interactions with this mock.
L
f E
chre
c A
Explication
JUnit
On peut aussi utiliser les annotations
class CalculTest {
Calcul calcul;
@Mock
CalculService calculService;
I c
@Rule
MockitoRule rule = MockitoJUnit.rule();
ELH
U
@BeforeEach
L MO
void setUp() throws Exception {
f E
hre
MockitoAnnotations.initMocks(this);
c
calcul = new Calcul(calculService);
}
@Test c A
void testSommeCarre() {
when(calculService.carre(2)).thenReturn(4);
when(calculService.carre(3)).thenReturn(9);
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
verify(calculService).carre(2);
}
// + les autres tests
JUnit
A c
Remplir les champs hre
c
Group Id avec org.eclipse
Artifact Id avec first-junit-maven
Package avec org.eclipse.main
JUnit
Vérifier l’existence des deux répertoires
/src/main/java : code source
... I c
ELH
U
L MO
S’il n’y a pas de src/main/java ou src/test/java
Aller dansc
Path > Configure Build Path...
Build
JUnit
Ajouter les dépendances suivantes dans pom.xml
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.2.0</version>
I c
<scope>test</scope>
</dependency>
ELH
U
MO
<dependency>
f E L
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.1</version>
chre
c A
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.23.0</version>
<scope>test</scope>
</dependency>
JUnit
Pour tester
I c
ELH
Annoter les classes de test par @RunWith(JUnitPlatform.class)
U
L MO
f E
chre
c A
JUnit
Pour tester
I c
ELH
Annoter les classes de test par @RunWith(JUnitPlatform.class)
U
L MO
La classe CalculTest
f E
package org.eclipse.main;
chre
c A
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
JUnit
JUnit
Utiliser @RepeatedTest pour répéter un test plusieurs fois
@RepeatedTest(3)
void testSomme(RepetitionInfo repetitionInfo) {
assertNotEquals(7, calcul.somme(repetitionInfo.
I c
getCurrentRepetition(),3));
ELH
} U
L MO
f E
chre
c A
JUnit
Utiliser @RepeatedTest pour répéter un test plusieurs fois
@RepeatedTest(3)
void testSomme(RepetitionInfo repetitionInfo) {
assertNotEquals(7, calcul.somme(repetitionInfo.
I c
getCurrentRepetition(),3));
ELH
} U
L MO
f E
chre
Explication c A
Il faut remplacer @Test par @RepeatedTest
Pour récupérer l’index de l’itération courante, on déclare un objet
de type RepetitionInfo
JUnit
JUnit
Utiliser @ParameterizedTest pour paramétrer un test
@DisplayName("Test de la methode somme")
@ParameterizedTest
@ValueSource(ints = {2, 3})
void testSomme(int t) {
I c
}
assertNotEquals(5, calcul.somme(t, 1));
ELH
U
L MO
f E
chre
c A
JUnit
Utiliser @ParameterizedTest pour paramétrer un test
@DisplayName("Test de la methode somme")
@ParameterizedTest
@ValueSource(ints = {2, 3})
void testSomme(int t) {
I c
}
assertNotEquals(5, calcul.somme(t, 1));
ELH
U
L MO
f E
hre
Explication
A c
Il faut remplacer @Test par @ParameterizedTest
c
Cette méthode sera testée deux fois, une fois pour la valeur 2 et une fois pour la
valeur 3
JUnit
JUnit
Pour activer ou désactiver un test selon le système d’exploitation, on utilise soit
@DisabledOnOs soit @EnabledOnOs
@Test
@DisabledOnOs(MAC)
void testSommeCarre() {
I c
when(calculService.Carre(2)).thenReturn(4);
when(calculService.Carre(3)).thenReturn(9);
ELH
U
MO
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
verify(calculService).Carre(2);
f E L
hre
}
c
c A
JUnit
Pour activer ou désactiver un test selon le système d’exploitation, on utilise soit
@DisabledOnOs soit @EnabledOnOs
@Test
@DisabledOnOs(MAC)
void testSommeCarre() {
I c
when(calculService.Carre(2)).thenReturn(4);
when(calculService.Carre(3)).thenReturn(9);
ELH
U
MO
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
verify(calculService).Carre(2);
f E L
hre
}
A c
c
Il faut importer la constante MAC
import static org.junit.jupiter.api.condition.OS.MAC;
JUnit
Pour activer ou désactiver un test selon le système d’exploitation, on utilise soit
@DisabledOnOs soit @EnabledOnOs
@Test
@DisabledOnOs(MAC)
void testSommeCarre() {
I c
when(calculService.Carre(2)).thenReturn(4);
when(calculService.Carre(3)).thenReturn(9);
ELH
U
MO
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
verify(calculService).Carre(2);
f E L
hre
}
A c
c
Il faut importer la constante MAC
import static org.junit.jupiter.api.condition.OS.MAC;
JUnit
Pour activer ou désactiver un test selon la version de JRE, on utilise soit
@DisabledOnJre soit @EnabledOnJre
@Test
@DisabledOnOs(MAC)
@EnabledOnJre(JAVA_10)
I c
void testSommeCarre() {
ELH
when(calculService.Carre(2)).thenReturn(4);
U
when(calculService.Carre(3)).thenReturn(9);
L MO
E
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
f
hre
verify(calculService).Carre(2);
c
c A
}
JUnit
Pour activer ou désactiver un test selon la version de JRE, on utilise soit
@DisabledOnJre soit @EnabledOnJre
@Test
@DisabledOnOs(MAC)
@EnabledOnJre(JAVA_10)
I c
void testSommeCarre() {
ELH
when(calculService.Carre(2)).thenReturn(4);
U
when(calculService.Carre(3)).thenReturn(9);
L MO
E
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
f
hre
verify(calculService).Carre(2);
c
c A
}
Il faut importer la constante JAVA 10
JUnit
Pour activer ou désactiver un test selon la version de JRE, on utilise soit
@DisabledOnJre soit @EnabledOnJre
@Test
@DisabledOnOs(MAC)
@EnabledOnJre(JAVA_10)
I c
void testSommeCarre() {
ELH
when(calculService.Carre(2)).thenReturn(4);
U
when(calculService.Carre(3)).thenReturn(9);
L MO
E
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
f
hre
verify(calculService).Carre(2);
c
c A
}
Il faut importer la constante JAVA 10
JUnit
Pour activer ou désactiver un test selon la valeur d’un test logique (on peut
même utiliser une expression régulière), on utilise soit @DisabledIf soit
@EnabledIf
I c
@Test
ELH
U
MO
@DisabledOnOs(MAC)
@DisabledIf("2 * 3 > 4")
void testSommeCarre() {
f E L
hre
when(calculService.Carre(2)).thenReturn(4);
c
c A
when(calculService.Carre(3)).thenReturn(9);
assertTrue(calcul.sommeCarre(2, 3) == 13, "calcul exact");
verify(calculService).Carre(2);
}
JUnit
Objectif
JUnit
Objectif
I c
Ou s’il y a des zones inaccessibles dans notre code
ELH
U
MO EclEmma
Pour cela, il faut installer un plugin Eclipse
L
e
Aller dans Help > rInstall
h f E New Software > Add
A cdans Name et http://update.eclemma.org/
c
Saisir EclEmma
dans Location
Cocher la case EclEmma et cliquer sur Next
Terminer l’installation et redémarrer Eclipse
JUnit