Tests Unitaires avec JUnit
Tests Unitaires avec JUnit
avec JUnit
Philippe Genoud
[Link]@[Link]
©
© Philippe
Philippe GENOUD
GENOUD UGA
UJF Janvier 2024
2012 1
Le problème du test
Tous les programmeurs savent qu’ils doivent écrire des tests, peu le font correctement..
Moins de
Augmentation temps pour écrire
de la pression des tests
Je suis trop
à la bourre !
test d'intégration
procédure visant à vérifier le bon fonctionnement d'un ensemble de composants formant tout ou partie d'un
logiciel : dans le test d’intégration, chacun des modules indépendants du logiciel est assemblé et testé dans
l’ensemble.
test système (ou test fonctionnel)
procédure visant à vérifier le bon fonctionnement du logiciel (système intégré) afin d'évaluer sa conformité aux
exigences spécifiées (Spécifications fonctionnelles et techniques des besoins)
test de performance (benchmark)
utilisé pour comparer les composants logiciels à plusieurs reprises. L'objectif est de garantir que le code testé
s'exécute assez rapidement, même s'il est soumis à une charge élevée.
Ce contrat définit:
les services proposés par la classe
la manière dont ces services doivent être
utilisés
Implémentation
Spécification Trace d’exécution
Programme de test
Vérification
Spécification
jugement humain
Risques d’erreur humaine
si une trace contient de nombreux print, perte
de lisibilité (Scroll Blindness)
Processus long et répétitif à renouveler chaque
fois que la classe est modifiée et/ou qu'un bug
est corrigé (test de non régression)
Inefficace et coûteux
Terminologie JUnit
Test unitaire (Unit test) : test d’une classe
Cas de test (Test case) : teste les réponses d’une méthode à un ensemble
particulier d’entrées
Suite de tests (Test suite) : une collection de cas de tests
organisation des
sources dans un
projet maven
[Link](r2); Failure:
le code ne correspond pas au critères de test, une
assertEquals(2, [Link]()); assertion n’est pas vérifiée
assertEquals(5, [Link]());
}
}
assertNull(Object object)
assertNull(Object object, String message)
assertNull(Object object, Supplier<String> messageSupplier)
Vérifie que object == null, sinon une AssertionFailedError est provoquée.
assertNotNull(Object object)
assertNotNull(Object object , String message)
assertNotNull(Object object , Supplier<String> messageSupplier)
Vérifie que la référence object n’est pas la valeur null, sinon une AssertionFailedError est provoquée.
fail()
fail(String message)
fail(Supplier<String> messageSupplier)
Provoque l’échec du test et lance une AssertionFailedError
Utile lorsque les autres méthodes assert ne correspondent pas exactement à vos besoins ou pour tester que certaines exceptions sont bien lancées.
Comment vérifier que des exceptions sont lancées comme prévu ? à la JUnit 3.8
@Test try {
public void testDenomNull() { // appel d’une méthode devant lancer une Exception
...
try { // si l'exception n'a pas eu lieu on force le
//test échouer
new Rational(3,0);
fail("Did not throw an ExpectedException");
fail("IllegalArgumentException non lancée"); }
catch (ExpectedException e) {
} }
catch (IllegalArgumentException e) {
// OK exception lancée
}
}
Vérifie que l'exception est bien levée La classe de Expression lambda contenant le code à
et renvoie l'objet exception l'exception exécuter provoquant l'exception
@Test
public void testDenomNull() {
IllegalArgumentException except = assertThrows([Link], () -> new Rational(10, 0) );
assertEquals("dénominateur nul interdit", [Link]());
}
@Test
public void testAdd() {
Code exécuté après chaque méthode de test
Rational r1 = new Rational(2, 3); @AfterEach
Rational r2 = new Rational(7, 5);
[Link](r2); public void tearDown() {
assertTrue(31 == [Link]()); ...
assertTrue(15 == [Link]()); ...
} }
}
setUp()
@BeforeAll
Code exécuté une seule fois avant de public static void setUpClass() {
... m1()
commencer l’exécution des méthodes de
}
test de la classe
tearDown() Ordre d’exécution
@AfterAll
Code exécuté une seule fois après avoir public static void tearDownClass() {
... setUp()
exécuté toutes les méthodes de test de la
}
classe m2()
@BeforeEach
public void setUp() { tearDown()
Code exécuté avant chaque méthode de ...
test de la classe }
tearDownClass()
@AfterEach
public void tearDown() {
Code exécuté après chaque méthode de
...
test de la classe }
@Test
public void m1() {
méthode de test ...
}
@Test
public void m2() {
On ne peut préjuger d’un ordre
méthode de test ... d’exécution des méthodes de test
}
} (@Test)
un exemple utilisant les deux annotations pour sélectionner deux classes de test et un package:
[Link]
package [Link];
import [Link];
import [Link];
import [Link]; classes dont tous les tests sont à exécuter
import [Link];
import [Link]; ces classes peuvent elles-mêmes
être des suites de de tests
@RunWith([Link])
@SelectClasses( { [Link], [Link] } )
@SelectPackages("[Link]")
public class TestSuiteDemo { package dont toutes les classes de test sont à exécuter
}
OpenClover [Link]
Cobertura [Link]
….
TDD Test Driven Development : écrire les tests avant les implémentations des classes
Intégration continue – Pendant le développement, le programme marche toujours – peut être qu’il ne fait pas
tout ce qui est requis mais ce qu’il fait il le fait bien.
[Link]
...
D’autres outils
outils de profiling
[Link]
JProfiler [Link]
VisualVM [Link]
…
Maven – JaCoCo code coverage example, mkyong , published November 15, 2018
[Link]
Le site [Link]
Comment vérifier que des exceptions sont lancées comme prévu ? à la JUnit 3.8
@Test try {
public void testDenomNull() { // appel d’une méthode devant lancer une Exception
...
try { // si l'exception n'a pas eu lieu on force le
//test échouer
new Rational(3,0); fail("Did not throw an ExpectedException");
fail("IllegalArgumentException non lancée"); }
catch (ExpectedException e) { }
}
catch (IllegalArgumentException e) {
// OK exception lancée
}
} Avec JUnit4 paramètre expected Le test échoue si l'exécution de la méthode dépasse le
de l'annotation @Test temps fixé par le paramètre timeout