Assertions JUnit en Java
Vérifiez le comportement dans JUnit 5 avec assertEquals, assertTrue, assertThrows, assertAll et bien d'autres méthodes.
Une assertion est le moment où un test cesse de décrire et commence à vérifier — elle énonce ce que le code doit produire et fait échouer le test si la réalité ne correspond pas. JUnit 5 (l'API Jupiter) regroupe toutes les assertions en tant que méthodes static sur une seule classe, org.junit.jupiter.api.Assertions. Maîtrisez cette poignée de méthodes et vous pourrez exprimer presque n'importe quelle attente : égalité, vérité, nullité, identité, exceptions levées, délais d'attente et vérifications groupées. Ce chapitre passe en revue celles que vous utilisez au quotidien.
Si vous débutez avec ce framework, lisez d'abord l'introduction à JUnit, puis les annotations JUnit pour comprendre d'où viennent les méthodes @Test. Les assertions se trouvent à l'intérieur de ces méthodes.
Le modèle mental : une assertion échouée fait échouer le test
Une méthode de test JUnit s'exécute de haut en bas. Chaque assertion qui est vérifiée est silencieuse ; la première qui n'est pas vérifiée lève une AssertionFailedError, que JUnit intercepte et enregistre comme un échec — la méthode s'arrête à ce stade. Les assertions sont donc les points de sortie du test. L'ordre conventionnel des arguments est attendu en premier, réel en second, et chaque méthode accepte un message final facultatif utilisé uniquement lorsque la vérification échoue :
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class CalculatorTest {
@Test
void addsTwoNumbers() {
int result = 2 + 3;
assertEquals(5, result, "2 + 3 should equal 5");
}
}Vous importez les méthodes de manière statique (import static ... Assertions.*) afin que le corps du test se lise comme de l'anglais courant — assertEquals(...), et non Assertions.assertEquals(...).
Égalité, vérité et nullité
Ces quatre catégories couvrent la grande majorité des assertions réelles :
| Méthode | Réussit quand |
|---|---|
assertEquals(expected, actual) | expected.equals(actual) est vrai |
assertNotEquals(unexpected, actual) | les deux ne sont pas égaux |
assertTrue(condition) / assertFalse(condition) | le booléen est true / false |
assertNull(obj) / assertNotNull(obj) | la référence est / n'est pas null |
assertSame(expected, actual) | les deux désignent le même objet (==) |
assertArrayEquals(expected, actual) | les tableaux sont égaux élément par élément |
assertEquals("HELLO", "hello".toUpperCase());
assertTrue(List.of(1, 2, 3).contains(2), "list should contain 2");
assertNull(map.get("missing"));
assertNotSame(new String("a"), new String("a")); // distinct objects
assertArrayEquals(new int[]{1, 2, 3}, computeRange(3));assertEquals utilise .equals(), donc deux objets String différents ayant les mêmes caractères passent ; assertSame utilise ==, donc ils échouent. Recourez à assertSame uniquement lorsque c'est l'identité de l'objet que vous souhaitez tester.
Tester les exceptions avec assertThrows
Un test affirme parfois que du code échoue — qu'une entrée invalide lève une exception. assertThrows prend le type d'exception et un lambda ; il réussit uniquement si l'exécution du lambda lève ce type (ou un sous-type), et il retourne l'exception interceptée afin que vous puissiez inspecter son message :
@Test
void rejectsNullName() {
IllegalArgumentException ex = assertThrows(
IllegalArgumentException.class,
() -> greet(null));
assertEquals("name must not be null", ex.getMessage());
}Son image miroir est assertDoesNotThrow, qui échoue si le lambda lève quoi que ce soit — utile pour affirmer qu'un chemin auparavant bogué s'exécute maintenant proprement. (Pour les règles régissant les exceptions que votre code lève, consultez Java exceptions.)
Regroupement avec assertAll
Par défaut, la première assertion échouée termine la méthode, masquant ainsi les problèmes suivants. assertAll exécute chaque assertion contenue même lorsque certaines échouent, puis rapporte tous les échecs ensemble — idéal pour vérifier plusieurs propriétés d'un même objet :
@Test
void buildsCompleteUser() {
User u = User.of("[email protected]");
assertAll("user",
() -> assertEquals("[email protected]", u.email()),
() -> assertTrue(u.isActive()),
() -> assertNotNull(u.createdAt()));
}Si l'e-mail et le drapeau actif sont tous deux incorrects, une seule exécution vous l'indique — au lieu de corriger l'un, de relancer et de découvrir le suivant.
Un exemple concret : une exécution de test auto-vérifiée, sans framework
L'exécuteur de code n'a pas JUnit dans son classpath, donc ce programme implémente la même idée en Java pur : de petits assistants assertEquals, assertTrue, assertThrows et assertAll qui se comportent comme ceux de Jupiter — silencieux en cas de succès, expressifs en cas d'échec — pilotant quelques méthodes sous test et affichant un bilan de type runner à la fin. L'API que vous utiliseriez réellement se trouve dans les blocs statiques ci-dessus ; celui-ci montre ce que ces méthodes font.
Ce qu'il faut retenir de l'exécution :
- Les vérifications réussies ne produisent aucune ligne d'échec — seuls
add(2,3) verified == 5ettag conditions verifieds'affichent, reflétant la règle de JUnit selon laquelle une assertion satisfaite est silencieuse et seuls les échecs s'expriment. assertThrowsa affichécaught expected IllegalArgumentException: name must not be null, illustrant le schéma : le lambda doit lever une exception, le type doit correspondre, et le message de l'exception interceptée vous appartient pour une assertion ultérieure.assertAll ran 3 checks, 0 failedconfirme le comportement de regroupement — les trois lambdas ont été exécutés et comptabilisés ensemble, ce qui est précisément la raison pour laquelleassertAllexpose chaque problème en un seul passage au lieu de s'arrêter au premier.- Le
SUMMARY -> passed: 7, failed: 0final comptabilise sept assertions individuelles dans l'ensemble du programme (une égalité, deux booléens, un throws et trois dansassertAll), le même bilan qu'un vrai runner rapporte — chaque appel àassertXest une vérification. - Rien ici n'a importé de framework de test, pourtant la structure est identique à Jupiter : des assistants silencieux en cas de succès et explicites en cas d'échec. Remplacer ceux-ci par
org.junit.jupiter.api.Assertions.*changerait les imports, pas la façon de raisonner sur chaque vérification.
L'ordre des arguments perturbe presque tout le monde au début : c'est assertEquals(expected, actual), jamais l'inverse. Intervertissez-les et le test fonctionnera quand même, mais un message d'échec sera à l'envers — il affirme que votre valeur correcte est fausse et que la valeur boguée est juste. Mettez toujours la valeur littérale ou connue-bonne en premier.
Que faire ensuite
Les assertions ne sont qu'une pièce d'une méthode de test. Pour les utiliser efficacement :
- Regroupez la configuration et le démontage autour d'elles avec les rappels du cycle de vie JUnit (
@BeforeEach,@AfterEach). - Exécutez les mêmes assertions sur de nombreuses entrées sans copier-coller en utilisant les tests paramétrés.
- Revisitez la référence des annotations pour
@Test,@DisplayNameet@Disabled.