Présentation de JUnit
JUnit est un framework de test unitaire spécifiquement conçu pour le langage Java. Développé initialement par Kent Beck et Erich Gamma, il s'inscrit dans la lignée des frameworks xUnit dérivés de sUnit. JUnit est aujourd'hui un outil incontournable, intégré dans la majorité des IDE Java, et bénéficie d'une large communauté proposant de nombreuses extensions.
En tant que framwork de test de régression, JUnit permet d'effectuer des tests de type boîte blanche, où le développeur connaît les mécanismes internes du code à valider. L'approche consiste à hériter de la classe de base pour construire des suites de tests automatisés.
Ses principales caractéristiques comprennent :
- Des assertions pour vérifier les résultats attendus
- Des fixtures pour préparer des données communes aux tests
- Des suites de tests pour organiser et exécuter les cas de test
- Des exécuteurs de tests sous forme graphique ou textuelle
Fonctionnalités clés
Annotations JUnit
| Annotation | Description |
|---|---|
| @Test | Marque une méthode comme cas de test. Peut inclure des paramètres tels que (expected=Exception.class) ou (timeout=xxx). |
| @Ignore | Indique qu'un test doit être ignoré lors de l'exécution. |
| @Before | Exécutée avant chaque méthode de test pour initialiser l'environnement. |
| @After | Exécutée après chaque méthode de test pour nettoyer les ressources. |
| @BeforeClass | Exécutée une seule fois avant l'ensemble des tests de la classe. |
| @AfterClass | Exécutée une seule fois après l'ensemble des tests de la classe. |
L'annoattion @Test est celle utilisée le plus fréquemment dans les projets.
Méthodes d'assertion
| Méthode | Description |
|---|---|
| assertArrayEquals(tableauAttendu, tableauActuel) | Vérifie l'égalité de deux tableaux. |
| assertEquals(valeurAttendue, valeurActuelle) | Compare deux objets pour l'égalité, similaire à l'utilisation de equals(). |
| assertNotEquals(premier, second) | Vérifie que deux objets ne sont pas égaux. |
| assertNull(objet) | Teste si une référence est nulle. |
| assertNotNull(objet) | Teste si une référence n'est pas nulle. |
| assertSame(referenceAttendue, referenceActuelle) | Vérifie que deux références pointent vers le même objet, équivalent à l'opérateur ==. |
| assertNotSame(referenceInattendue, referenceActuelle) | Vérifie que deux références ne pointent pas vers le même objet, équivalent à !=. |
| assertTrue(condition) | Évalue qu'une condition booléenne est vraie. |
| assertFalse(condition) | Évalue qu'une condition booléenne est fausse. |
| assertThat(valeurActuelle, matcher) | Vérifie qu'une valeur satisfait un critère spécifique via un matcher. |
| fail() | Force l'échec d'un test. |
Les méthodes les plus couramment employées sont assertEquals, assertNotEquals, assertTrue et assertFalse.
Exemple pratique de test unitaire
Considérons une classe utilitarie pour des opérations mathématiques :
public class Calculatrice {
/**
* Retourne la somme de deux entiers.
*/
public int addition(int a, int b) {
return a + b;
}
/**
* Retourne le quotient de la division entière.
* @throws ArithmeticException si le diviseur est zéro.
*/
public int diviser(int dividend, int diviseur) {
if (diviseur == 0) {
throw new ArithmeticException("Division par zéro non autorisée.");
}
return dividend / diviseur;
}
}
Voici la classe de test correspondante :
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.rules.Timeout;
import java.util.concurrent.TimeUnit;
public class CalculatriceTest {
@Rule
public Timeout timeoutRule = new Timeout(200, TimeUnit.MILLISECONDS);
@Test
public void testAdditionSimple() {
Calculatrice calc = new Calculatrice();
int resultat = calc.addition(3, 5);
assertEquals(8, resultat);
}
@Test
public void testAdditionAvecDelai() throws InterruptedException {
Thread.sleep(250);
Calculatrice calc = new Calculatrice();
calc.addition(10, 20);
}
@Test
public void testDivisionParZero() {
Calculatrice calc = new Calculatrice();
assertThrows(ArithmeticException.class, () -> calc.diviser(15, 0));
}
@Ignore("Test temporairement désactivé pour révision")
@Test
public void testAdditionInvalide() {
Calculatrice calc = new Calculatrice();
int resultat = calc.addition(4, 6);
assertEquals(11, resultat);
}
}
Bonnes pratiques et considérations
- Nommage explicite : Utilisez des noms descriptifs pour les classes et méthodes de test. Par exemple, une méthode testant la fonction addition pourrait s'appeler testAddition.
- Isolation des tests : Chaque test doit être indépendant et ne pas reposer sur l'état laissé par un autre test. JUnit ne garantit pas l'ordre d'exécution par défaut.
- Documentation : Ajoutez des commentaires clairs dans les tests pour expliquer leur objectif et les scénarios couverts, facilitant ainsi la maintenance.
- Gestion des exceptions : Pour les méthodes susceptibles de lever des exceptions, utilisez assertThrows afin de valider le comportement attendu.
- Contrôle du temps d'exécution : Appliquez des annotations ou des règles de timeout pour détecter les boucles infinies ou les opérations trop lentes, comme illustré avec la règle Timeout dans l'exemple.