@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll

@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll

1. introduction

Dans ce court tutoriel, nous allons expliquer les différences entre les annotations@Before,@BeforeClass,@BeforeEach et@BeforeAll dans JUnit 4 et 5 - avec des exemples pratiques de pour les utiliser.

Nous aborderons également brièvement leurs annotations complémentaires@After.

Commençons par JUnit 4.

2. @Before

Methods annotated with the @Before annotation are executed before each test. Ceci est utile lorsque nous voulons exécuter du code commun avant d'exécuter un test.

Voyons un exemple où nous initialisons une liste et ajoutons quelques valeurs:

@RunWith(JUnit4.class)
public class BeforeAndAfterAnnotationsUnitTest {

    // ...

    private List list;

    @Before
    public void init() {
        LOG.info("startup");
        list = new ArrayList<>(Arrays.asList("test1", "test2"));
    }

    @After
    public void finalize() {
        LOG.info("finalize");
        list.clear();
    }
}

Notez que nous avons également ajouté une autre méthode annotée avec@After afin de vider la liste après l'exécution de chaque test.

Après cela, ajoutons quelques tests pour vérifier la taille de notre liste:

@Test
public void whenCheckingListSize_thenSizeEqualsToInit() {
    LOG.info("executing test");
    assertEquals(2, list.size());

    list.add("another test");
}

@Test
public void whenCheckingListSizeAgain_thenSizeEqualsToInit() {
    LOG.info("executing another test");
    assertEquals(2, list.size());

    list.add("yet another test");
}

Dans ce cas,it’s crucial to make sure that test environment is properly set up before running each test puisque la liste est modifiée à chaque exécution de test.

Si nous regardons la sortie du journal, nous pouvons vérifier que les méthodesinit etfinalize ont été exécutées une fois par test:

... startup
... executing another test
... finalize
... startup
... executing test
... finalize

3. @BeforeClass

Lorsque nous voulons exécuter une opération commune coûteuse avant chaque test,it’s preferable to execute it only once before running all tests using @BeforeClass. Quelques exemples d'opérations coûteuses courantes sont la création d'une connexion à une base de données ou le démarrage d'un serveur.

Créons une classe de test simple qui simule la création d’une connexion à une base de données:

@RunWith(JUnit4.class)
public class BeforeClassAndAfterClassAnnotationsUnitTest {

    // ...

    @BeforeClass
    public static void setup() {
        LOG.info("startup - creating DB connection");
    }

    @AfterClass
    public static void tearDown() {
        LOG.info("closing DB connection");
    }
}

Notez quethese methods have to be static, donc ils seront exécutés avant d'exécuter les tests de la classe.

Comme nous l'avons fait auparavant, ajoutons également quelques tests simples:

@Test
public void simpleTest() {
    LOG.info("simple test");
}

@Test
public void anotherSimpleTest() {
    LOG.info("another simple test");
}

Cette fois, si nous regardons la sortie du journal, nous pouvons vérifier que les méthodessetup ettearDown n'ont été exécutées qu'une seule fois:

... startup - creating DB connection
... simple test
... another simple test
... closing DB connection

4. @BeforeEach et@BeforeAll

@BeforeEach and @BeforeAll are the JUnit 5 equivalents of @Before and @BeforeClass. Ces annotations ont été renommées avec des noms plus clairs pour éviter toute confusion.

Reproduisons nos classes précédentes en utilisant ces nouvelles annotations, en commençant par les annotations@BeforeEach et@AfterEach:

@RunWith(JUnitPlatform.class)
class BeforeEachAndAfterEachAnnotationsUnitTest {

    // ...

    private List list;

    @BeforeEach
    void init() {
        LOG.info("startup");
        list = new ArrayList<>(Arrays.asList("test1", "test2"));
    }

    @AfterEach
    void finalize() {
        LOG.info("finalize");
        list.clear();
    }

    // ...
}

Si nous vérifions les journaux, nous pouvons confirmer que cela fonctionne de la même manière qu'avec les annotations@Before et@After:

... startup
... executing another test
... finalize
... startup
... executing test
... finalize

Enfin, faisons de même avec l'autre classe de test pour voir les annotations@BeforeAll et@AfterAll en action:

@RunWith(JUnitPlatform.class)
public class BeforeAllAndAfterAllAnnotationsUnitTest {

    // ...

    @BeforeAll
    public static void setup() {
        LOG.info("startup - creating DB connection");
    }

    @AfterAll
    public static void tearDown() {
        LOG.info("closing DB connection");
    }

    // ...
}

Et le résultat est le même qu'avec l'ancienne annotation:

... startup - creating DB connection
... simple test
... another simple test
... closing DB connection

5. Conclusion

Dans cet article, nous avons montré les différences entre les annotations@Before,@BeforeClass,@BeforeEach et@BeforeAll dans JUnit et quand chacune d'elles doit être utilisée.

Comme toujours, le code source complet des exemples est disponibleover on GitHub.