@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll

1. Introduzione

In questo breve tutorial, spiegheremo le differenze tra le annotazioni @Before , @BeforeClass , @BeforeEach e @BeforeAll in JUnit 4 e 5, con esempi pratici di come usarle.

Tratteremo anche brevemente le loro annotazioni complementari @After .

Cominciamo con JUnit 4.

2. @Before

I metodi annotati con l' annotazione @Before vengono eseguiti prima di ogni test. Ciò è utile quando vogliamo eseguire del codice comune prima di eseguire un test.

Vediamo un esempio in cui inizializziamo un elenco e aggiungiamo alcuni valori:

@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 teardown() { LOG.info("teardown"); list.clear(); } }

Si noti che abbiamo anche aggiunto un altro metodo annotato con @After per cancellare l'elenco dopo l'esecuzione di ogni test.

Successivamente, aggiungiamo alcuni test per verificare la dimensione del nostro elenco:

@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"); }

In questo caso, è fondamentale assicurarsi che l'ambiente di test sia configurato correttamente prima di eseguire ogni test poiché l'elenco viene modificato durante ogni esecuzione del test.

Se diamo uno sguardo all'output del log possiamo verificare che i metodi init e teardown siano stati eseguiti una volta per test:

... startup ... executing another test ... teardown ... startup ... executing test ... teardown

3. @BeforeClass

Quando vogliamo eseguire un'operazione comune costosa prima di ogni test, è preferibile eseguirla solo una volta prima di eseguire tutti i test utilizzando @BeforeClass . Alcuni esempi di operazioni costose comuni sono la creazione di una connessione al database o l'avvio di un server.

Creiamo una semplice classe di test che simuli la creazione di una connessione al database:

@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"); } }

Si noti che questi metodi devono essere statici , quindi verranno eseguiti prima di eseguire i test della classe.

Come abbiamo fatto prima, aggiungiamo anche alcuni semplici test:

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

Questa volta, se diamo uno sguardo all'output del log possiamo verificare che i metodi setup e tearDown siano stati eseguiti una sola volta:

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

4. @BeforeEach e @BeforeAll

@BeforeEac he @BeforeAll sono gli equivalenti JUnit 5 di @Before e @BeforeClass . Queste annotazioni sono state rinominate con nomi più chiari per evitare confusione.

Duplichiamo le nostre classi precedenti usando queste nuove annotazioni, iniziando con le annotazioni @BeforeEach e @AfterEach :

@RunWith(JUnitPlatform.class) class BeforeEachAndAfterEachAnnotationsUnitTest { // ... private List list; @BeforeEach void init() { LOG.info("startup"); list = new ArrayList(Arrays.asList("test1", "test2")); } @AfterEach void teardown() { LOG.info("teardown"); list.clear(); } // ... }

Se controlliamo i log, possiamo confermare che funziona allo stesso modo delle annotazioni @Before e @After :

... startup ... executing another test ... teardown ... startup ... executing test ... teardown

Infine, facciamo lo stesso con l'altra classe di test per vedere le annotazioni @BeforeAll e @AfterAll in azione:

@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"); } // ... }

E l'output è lo stesso della vecchia annotazione:

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

5. conclusione

In questo articolo, abbiamo mostrato le differenze tra le annotazioni @Before , @BeforeClass , @BeforeEach e @BeforeAll in JUnit e quando ciascuna di esse dovrebbe essere utilizzata.

Come sempre, il codice sorgente completo degli esempi è disponibile su GitHub.