Tests unitaires - Moodle INSA Rouen

publicité
Introduction JUnit Assertions Exécution
Introduction JUnit Assertions Exécution
Programmation
- Tests unitaires : JUNIT -
1
Introduction
Présentation
Framework de tests unitaires
2
JUnit
TestCase
Avant / Après les tests
3
Assertions
Méthodes classiques
Méthode basée sur des contrats
4
Exécution
Cas de Test
Suite de test
Nicolas Malandain
March 10, 2010
as
as
Architecture des Systèmes d’Information
Tests Unitaires
Introduction JUnit Assertions Exécution
Architecture des Systèmes d’Information
Tests Unitaires
1 / 27
Présentation Framework de tests unitaires
Introduction JUnit Assertions Exécution
Objectif des tests unitaires
2 / 27
Présentation Framework de tests unitaires
xUnit
S’assurer du bon fonctionnement
d’une partie ou de la totalité d’un logiciel
Bibliothèques xUnit disponibles pour de nombreux langages
AUnit (Ada)
JUnit (Java)
Utilisation
vérifier que le code répond aux spécification fonctionnelles
FLEXUnit (Adobe Flex)
NUnit (.NET)
permettre de tester facilement le code
JSUnit (Javascript)
lors de modification de code, vérifier qu’il n’y a pas de régression
CPPUnit (C++)
Les tests unitaires étaient très utilisés pour des applications critiques. La
méthode agile XP (eXtreme Programming) les place maintenant au
centre du processus de développement
Tests Unitaires
3 / 27
...
Tests Unitaires
4 / 27
Introduction JUnit Assertions Exécution
Présentation Framework de tests unitaires
Introduction JUnit Assertions Exécution
TestCase Avant / Après les tests
Le framework JUnit
Principe des annotations en Java
Créé par Kent Beck et Erich Gamma
Méta-données
ajout de méta-données (déclaratif) dans le code source qui seront
accessibles à la compilation et à l’exécution (par réflexion).
Principe
un environnement de développement simple
Deux exemples :
un test = un objet
public
vérification “à la chaı̂ne” des tests
depuis la version 4.x utilisation des annotations java
}
Tests Unitaires
Introduction JUnit Assertions Exécution
class A {
public
@Deprecated
public void laMethode() {
...
}
public void methodeA() {
...
}
5 / 27
class B extends A {
@Override
public void methodeA() {
...
}
}
Tests Unitaires
TestCase Avant / Après les tests
Introduction JUnit Assertions Exécution
6 / 27
TestCase Avant / Après les tests
Vocabulaire JUnit
Test des méthodes d’une classe
Test case (Cas de test)
Principe
création d’une classe de test pour chaque classe à tester
annotation des méthodes de test par @Test
classe regroupant un ensemble de tests généralement liés à une classe à
tester
Syntaxe (package org.junit)
Test
méthode effectuant un test
import org.junit.Test
public class TestDeLaClasse {
Fixture
contenu commun aux tests d’un cas de test
@Test
public void testConstructeur() {
// utilisation d’assertions
}
Test Suite
enchaı̂nement de cas de test
@Test
public void testMethode1() {
// utilisation d’assertions
}
}
Tests Unitaires
7 / 27
...
Tests Unitaires
8 / 27
Introduction JUnit Assertions Exécution
TestCase Avant / Après les tests
Introduction JUnit Assertions Exécution
TestCase Avant / Après les tests
Paramétrage de @Test
Exécution de code avant et après chaque test
@Test(timeout=durée )
Le test déclaré avec un timeout échoue si la méthode annotée prend plus
de temps que la durée (ms) indiquée .
Objectifs
Préparer un contexte avant chaque test et le nettoyer après chaque test
allocation/désallocation de ressources, initialisation d’objets “fixes”
(fixtures)
@Test(expected=ClasseException.class )
Exemples d’utilisation
Le test déclaré avec une classe d’exception doit lancer cette exception
sinon le test échoue.
allocation de ressources avant un test (création d’un fichier) et
suppression de ces ressources après le test (destruction d’un fichier)
création d’objets commun à chaque test
@Ignore
Une annotation @Test précédée d’un @Ignore permet de ne pas passer
le test.
Tests Unitaires
Introduction JUnit Assertions Exécution
Syntaxe
Utilisation des annotations @Before et @After devant les méthodes
correspondantes
9 / 27
Tests Unitaires
TestCase Avant / Après les tests
Introduction JUnit Assertions Exécution
Exécution de code avant et après chaque cas de test
10 / 27
Méthodes classiques Méthode basée sur des contrats
Présentation des assertions
Assertion (linguistique/philosophique)
“Une assertion représente un énoncé considéré ou présenté comme vrai”a
Objectif
Initialisation d’objets fixes commun aux tests : objets constant, singleton,
ou encore ayant un temps de préparation très long.
Syntaxe
Annotations de méthodes public static void avec @BeforeClass et
@AfterClass.
a
wikipedia
Assertion (mathématique/logique)
“Une assertion est une proposition mathématique vraie. Cette
proposition vraie s’inscrit dans le cadre d’une théorie précisée”a
a
wikipedia
D’un point de vue génie logiciel
Les assertions permettent de vérifier des hypothèses de conceptiona
a
Tests Unitaires
11 / 27
Java in a Nutshell, Fifth edition (O’REILLY)
Tests Unitaires
12 / 27
Introduction JUnit Assertions Exécution
Les assertions de base de java
Méthodes classiques Méthode basée sur des contrats
Introduction JUnit Assertions Exécution
classe org.junit.Assert
Méthodes classiques Méthode basée sur des contrats
Exemple avec assertions classiques 1 / 3
TestAmpouleClassique.java
import
import
import
import
import
import
Quelques méthodes de classe :
assertEquals(..., ...) / assertArrayEquals(..., ...)
teste l’égalité des types simples, des objets et des tableaux
assertSame(Object, Object) teste qu’il s’agit du même objet
public Ampoule ampoule;
@Before
public void avantTest() {
ampoule = new Ampoule();
}
...
Remarque : un commentaire (String) d’assertion peut être passer en 1◦
paramètre pour expliquer la raison de l’échec d’une assertion
Introduction JUnit Assertions Exécution
@Test(timeout=1000)
public void test_basculer() {
boolean etat = ampoule.getEtat();
assertFalse(etat);
assertTrue(ampoule.basculer());
assertTrue(ampoule.getEtat());
while (etat != ampoule.getEtat()) {
etat=ampoule.getEtat();
ampoule.basculer();
}
assertFalse(ampoule.getEtat());
}
public class TestAmpouleClassique {
assertTrue(boolean)/assertFalse(boolean) teste le résultat
d’une expression logique
Tests Unitaires
@Ignore
@Test
public void test_SetGetCouleur() {
ampoule.setCouleur(Color.RED);
assertEquals(ampoule.getCouleur(), Color.BLUE);
}
org.junit.After;
static org.junit.Assert.*;
org.junit.Before;
org.junit.Ignore;
org.junit.Test;
java.awt.Color;
@Test
public void test_construteurs() {
assertEquals(ampoule.getCouleur(), Color.WHITE); }
assertFalse(ampoule.getEtat());
assertEquals((new Ampoule(Color.BLUE)).getCouleur(),Color.BLUE);
}
13 / 27
Méthodes classiques Méthode basée sur des contrats
Tests Unitaires
Introduction JUnit Assertions Exécution
Exemple avec assertions classiques 2 / 3
14 / 27
Méthodes classiques Méthode basée sur des contrats
Exemple avec assertions classiques 3 / 3
Exécution Échec : ( @Ignore )
JUnit version 4.5
.Before
After
.Before
After
E.Before
After
Exécution OK
JUnit version 4.5
.Before
After
I.Before
After
Time: 0,023
There was 1 failure:
1) test_SetGetCouleur(TestAmpouleClassique)
java.lang.AssertionError: expected:<java.awt.Color[r=255,g=0,b=0]> but was:<java.awt.Color[r=0,g=0,b=255]>
at org.junit.Assert.fail(Assert.java:91)
at org.junit.Assert.failNotEquals(Assert.java:618)
...
at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:116)
at org.junit.runner.JUnitCore.run(JUnitCore.java:107)
at org.junit.runner.JUnitCore.runMain(JUnitCore.java:88)
at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:54)
at org.junit.runner.JUnitCore.main(JUnitCore.java:46)
Time: 0,017
OK (1 test)
FAILURES!!!
Tests run: 3, Failures: 1
Tests Unitaires
15 / 27
Tests Unitaires
16 / 27
Introduction JUnit Assertions Exécution
Méthodes classiques Méthode basée sur des contrats
Introduction JUnit Assertions Exécution
Remarques 1 / 2
Méthodes classiques Méthode basée sur des contrats
Remarques 2 / 2
Comparaison de 2 valeurs
@Test
public void testNonExplicite1() {
int x = 5;
assertTrue(x>10);
}
@Test
public void testExpliciteAMaintenir() {
int x = 5;
assertTrue(x+" n’est pas supérieur à 10",x>10);
}
Constations
par défaut pas de message explicite de l’échec
comment assurer la cohérence du message avec l’assertion dans le
temps ?
rq : il y a redondance entre l’assertion et le message
pas de réelles combinaisons d’assertions possible
Exécution
1) testNonExplicite1(TestNonExplicite)
java.lang.AssertionError:
at org.junit.Assert.fail(Assert.java:91)
at org.junit.Assert.assertTrue(Assert.java:43)
...
2) testExpliciteAMaintenir(TestNonExplicite)
java.lang.AssertionError: 5 n’est pas supérieur à 10
at org.junit.Assert.fail(Assert.java:91)
at org.junit.Assert.assertTrue(Assert.java:43)
Tests Unitaires
Introduction JUnit Assertions Exécution
=⇒ les assertions à base de contrat
Méthodes classiques Méthode basée sur des contrats
Introduction JUnit Assertions Exécution
Les assertions basées sur des contrats 1 / 2
18 / 27
Méthodes classiques Méthode basée sur des contrats
Les assertions basées sur des contrats 2 / 2
La bibliothèque JMock
API permettant d’énoncer des contraintes sur la valeur d’un objet et de
les combiner.
Bibliothèque découpée en 7 parties :
org.hamcrest.beans
org.hamcrest.collection
org.hamcrest.core
org.hamcrest.number
org.hamcrest.object
org.hamcrest.text
Insertion de JMock dans JUnit 4
ajout de org.hamcrest.core dans JUnit.
Contrats disponibles :
AllOf
IsEqual
AnyOf
IsInstanceOf
DescribedAs
IsNot
Is
IsNull
IsAnything
IsSame
Déclaration des contrats avec la classe Assert
org.hamcrest.xml
Tests Unitaires
Tests Unitaires
17 / 27
public static <T> void assertThat(T actual, org.hamcrest.Matcher<T> matcher)
19 / 27
Tests Unitaires
20 / 27
Introduction JUnit Assertions Exécution
Méthodes classiques Méthode basée sur des contrats
Introduction JUnit Assertions Exécution
Exemple avec assertions à contrats 1 / 1
Méthodes classiques Méthode basée sur des contrats
Des messages explicites
TestAmpoule.java
Test de comparaison
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.hamcrest.core.IsEqual;
import org.junit.Test;
import java.awt.Color;
// Attention import static
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
public class TestAmpoule {
public Ampoule ampoule;
@Before
public void avantTest() {
ampoule = new Ampoule();
}
@Test
public void test_SetGetCouleur() {
ampoule.setCouleur(Color.RED);
assertThat(ampoule.getCouleur(),
IsEqual.equalTo(Color.RED));
}
import org.hamcrest.number.OrderingComparisons;
...
@Test
public void testExplicite() {
int x = 50;
assertThat(x, OrderingComparisons.lessThan(10));
}
@Test(timeout=1000)
public void test_basculer() {
boolean etat = ampoule.getEtat();
assertThat(etat, is(false));
assertThat(ampoule.basculer(), is(true));
assertThat(ampoule.getEtat(), is(true));
while (etat != ampoule.getEtat()) {
etat=ampoule.getEtat();
ampoule.basculer();
}
assertThat(ampoule.getEtat(), is(false));
}
Test de comparaison en erreur
java.lang.AssertionError:
Expected: a value less than <10>
got: <50>
@Test
}
public void test_construteurs() {
assertThat(ampoule.getCouleur(), IsEqual.equalTo(Color.WHITE));
assertThat(ampoule.getEtat(), is(false));
assertThat((new Ampoule(Color.BLUE)).getCouleur(), IsEqual.equalTo(Color.BLUE));
}
Tests Unitaires
Introduction JUnit Assertions Exécution
...
at
at
at
at
at
org.junit.Assert.assertThat(Assert.java:750)
org.junit.Assert.assertThat(Assert.java:709)
TestNonExplicite.testExplicite(TestNonExplicite.java:29)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
Tests Unitaires
21 / 27
Méthodes classiques Méthode basée sur des contrats
Introduction JUnit Assertions Exécution
Exemples de contrats
22 / 27
Méthodes classiques Méthode basée sur des contrats
Exemple de combinaison de contrats
Code
import
import
import
import
import
import
...
Contrats de base
IsSame.sameInstance(...)
IsEqual.equalTo(...)
IsInstanceOf.instanceOf(...)
Is.is(...) comportement selon la valeur (classe, égalité, contrat)
Combinaison de contrats
AllOf.allOf( les contrats )
@Test
public void testCombinaisonContrats() {
int x = 150;
assertThat(x, anyOf(allOf(lessThan(100), greaterThan(50)), is(42)));
}
Exécution
There was 1 failure:
1) testCombinaisonContrats(TestNonExplicite)
java.lang.AssertionError:
Expected: ((a value less than <100> and a value greater than <50>) or is <42>)
got: <150>
AnyOf.anyOf( les contrats )
...
Tests Unitaires
static org.junit.Assert.*;
static org.hamcrest.core.Is.is;
static org.hamcrest.core.AllOf.allOf;
static org.hamcrest.core.AnyOf.anyOf;
org.junit.Test;
static org.hamcrest.number.OrderingComparisons.*;
23 / 27
at org.junit.Assert.assertThat(Assert.java:750)
at org.junit.Assert.assertThat(Assert.java:709)
Tests Unitaires
24 / 27
Introduction JUnit Assertions Exécution
Cas de Test Suite de test
Introduction JUnit Assertions Exécution
Exécution d’un cas de test
Cas de Test Suite de test
Déclaration d’une suite
Les annotations @RunWith et @SuiteClasses
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
Ajout au CLASSPATH
JUnit
/chemin-junit /junit-4.5.jar
@RunWith(Suite.class)
@SuiteClasses({
CasDeTest1 ou Suite1 ,
CasDeTest2 ou Suite2 ,
...
})
JMock
/chemin-jmock /jmock-2.5.1.jar
/chemin-jmock /hamcrest-core-1.1.jar
/chemin-jmock /hamcrest-library-1.1.jar
public class NomDeLaSuite {
// classe vide
}
Appel
java org.junit.runner.JUnitCore casdetest
Exécution d’une Suite
java org.junit.runner.JUnitCore NomDeLaSuite
Tests Unitaires
Introduction JUnit Assertions Exécution
25 / 27
Cas de Test Suite de test
Exemple
SuiteA.java
SuiteB.java
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({
Test1A.class,
Test2A.class
})
public class SuiteA {}
@RunWith(Suite.class)
@SuiteClasses({
Test1B.class,
Test2B.class,
Test3B.class
})
public class SuiteB {}
AllTests.java
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@Suite.SuiteClasses({
SuiteA.class,
SuiteB.class
})
public class AllTests {}
Tests Unitaires
27 / 27
Tests Unitaires
26 / 27
Téléchargement