W3docs

Annotations JUnit en Java

Annotations essentielles de JUnit 5 — @Test, @BeforeEach, @AfterEach, @BeforeAll, @AfterAll, @Disabled.

JUnit 5 est le framework de test standard pour Java, et presque tout ce que vous lui indiquez passe par des annotations. Vous n'écrivez pas de méthode main ni n'appelez vous-même des méthodes ; vous décorez des méthodes ordinaires avec des annotations comme @Test, @BeforeEach et @AfterAll, et le moteur JUnit les découvre par réflexion et les exécute dans le bon ordre. Ce chapitre couvre les annotations de cycle de vie principales — ce que chacune signifie, quand elle se déclenche, et comment elles se combinent pour donner à chaque test un contexte propre et isolé.

Si vous êtes nouveau dans ce framework, commencez par l'introduction à JUnit ; pour les fonctions d'assertion appelées par ces tests, consultez les assertions JUnit. Les annotations elles-mêmes sont une fonctionnalité générale de Java couverte dans les annotations Java.

Les annotations se trouvent dans org.junit.jupiter.api

L'API de JUnit 5 est le module Jupiter. Les annotations que vous utilisez au quotidien proviennent toutes d'un seul package :

AnnotationS'applique àS'exécute
@Testune méthodeune fois par méthode de test
@BeforeEachune méthodeavant chaque @Test
@AfterEachune méthodeaprès chaque @Test
@BeforeAllune méthode staticune fois, avant tout test de la classe
@AfterAllune méthode staticune fois, après tous les tests de la classe
@Disabledune méthode ou une classejamais (ignorée et signalée)
@DisplayNameune méthode ou une classedéfinit un nom lisible dans les rapports

Une méthode annotée @Test n'a pas besoin du modificateur public dans JUnit 5 (package-private convient) et doit retourner void.

@Test : l'unité de travail

Une méthode de test effectue des assertions avec les méthodes statiques de org.junit.jupiter.api.Assertions. Si une assertion échoue, elle lève une exception, et le moteur enregistre ce test comme échoué sans arrêter les autres.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    @Test
    void addsTwoNumbers() {
        Calculator calc = new Calculator();
        assertEquals(5, calc.add(2, 3));
    }

    @Test
    void throwsOnDivideByZero() {
        Calculator calc = new Calculator();
        assertThrows(ArithmeticException.class, () -> calc.divide(1, 0));
    }
}

Chaque @Test s'exécute sur une nouvelle instance de la classe de test — JUnit construit un nouvel objet par test par défaut, de sorte que les champs définis dans un test ne peuvent pas fuiter dans un autre.

@BeforeEach et @AfterEach : les contextes par test

La configuration dont chaque test a besoin va dans une méthode @BeforeEach ; le nettoyage va dans @AfterEach. Elles encadrent chaque @Test, donnant à chaque test un point de départ identique.

import org.junit.jupiter.api.*;

class OrderServiceTest {

    private OrderService service;

    @BeforeEach
    void setUp() {
        service = new OrderService(new InMemoryRepo()); // fresh state per test
    }

    @AfterEach
    void tearDown() {
        service.close(); // runs even if the test threw
    }

    @Test
    void placesOrder() {
        assertTrue(service.place("SKU-1", 2));
    }
}

@AfterEach s'exécute même quand le test échoue, ce qui en fait l'endroit idéal pour libérer les ressources ouvertes dans @BeforeEach.

@BeforeAll et @AfterAll : une fois par classe

Quand la configuration est coûteuse et partageable — un conteneur de base de données, un serveur embarqué démarré — utilisez @BeforeAll pour le faire une seule fois et @AfterAll pour le démonter une seule fois. Comme elles s'exécutent avant qu'aucune instance n'existe, elles doivent être static.

import org.junit.jupiter.api.*;

class RepositoryTest {

    static Database db;

    @BeforeAll
    static void startDatabase() {
        db = Database.start();   // runs once, before everything
    }

    @AfterAll
    static void stopDatabase() {
        db.stop();               // runs once, after everything
    }

    @Test
    void savesRow() {
        assertEquals(1, db.insert("hello"));
    }
}

L'ordre complet du cycle de vie pour une classe avec deux tests est : @BeforeAll → (@BeforeEach@Test@AfterEach) → (@BeforeEach@Test@AfterEach) → @AfterAll. Le chapitre sur le cycle de vie JUnit présente cet ordre en détail, notamment comment il interagit avec la création d'instances.

@Disabled : ignorer sans supprimer

@Disabled désactive un test (ou une classe entière). Le moteur le signale comme ignoré plutôt que réussi ou échoué, de sorte qu'il reste visible. Donnez toujours une raison.

@Test
@Disabled("flaky until the rate-limiter fix lands — see JIRA-1234")
void callsExternalApi() {
    // not executed
}

Un exemple concret : un mini moteur de test

Il n'y a pas de jar JUnit sur cet environnement, donc le programme ci-dessous construit un mini moteur avec exactement la même structure que JUnit. Il déclare des annotations marqueurs (@BeforeAll, @BeforeEach, @Test, @AfterEach, @AfterAll, @Disabled), définit une petite classe de test annotée, puis utilise la réflexion — exactement ce que fait le moteur de JUnit en interne — pour découvrir et exécuter les méthodes dans l'ordre du cycle de vie et afficher un résumé réussi/échoué/ignoré.

java— editable, runs on the server

Ce que l'exécution illustre :

  • @BeforeAll s'affiche exactement une fois en haut et @AfterAll exactement une fois en bas — la configuration et le démontage au niveau de la classe encadrent toute l'exécution, c'est pourquoi JUnit exige qu'ils soient static.
  • Chaque @Test exécuté est précédé d'une ligne @BeforeEach et suivi d'une ligne @AfterEach, de sorte que chaque test s'est exécuté contre un contexte fraîchement préparé et a nettoyé après lui-même — l'encadrement par test qui maintient l'indépendance des tests.
  • La méthode flaky portait @Disabled, donc elle a affiché (skipped via @Disabled) et son corps n'a jamais été exécuté ; l'assertion échouante à l'intérieur n'a jamais été atteinte, ce qui est tout l'intérêt de désactiver plutôt que de supprimer.
  • La boucle de découverte n'agit que sur les méthodes où isAnnotationPresent(Test.class) est vrai — les annotations ne sont que des métadonnées, et c'est le moteur qui les lit via la réflexion qui les transforme en comportement, exactement comme le fait le vrai JUnit.
  • La dernière ligne rapporte 2 passed, 0 failed, 1 skipped : deux vrais tests ont réussi, aucun n'a échoué, et le test désactivé a été comptabilisé comme ignoré plutôt que silencieusement omis — la même comptabilité réussi/échoué/ignoré qu'un rapport JUnit vous fournit.

Pratique

Pratique
Dans JUnit 5, pourquoi une méthode annotée avec @BeforeAll doit-elle être déclarée static ?
Dans JUnit 5, pourquoi une méthode annotée avec @BeforeAll doit-elle être déclarée static ?
Was this page helpful?