@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll

1. Introducción

En este breve tutorial, explicaremos las diferencias entre las anotaciones @Before , @BeforeClass , @BeforeEach y @BeforeAll en JUnit 4 y 5, con ejemplos prácticos de cómo usarlas.

También cubriremos brevemente sus anotaciones complementarias @After .

Comencemos con JUnit 4.

2. @Antes

Los métodos anotados con la anotación @Before se ejecutan antes de cada prueba. Esto es útil cuando queremos ejecutar algún código común antes de ejecutar una prueba.

Veamos un ejemplo donde inicializamos una lista y agregamos algunos valores:

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

Observe que también agregamos otro método anotado con @After para borrar la lista después de la ejecución de cada prueba.

Después de eso, agreguemos algunas pruebas para verificar el tamaño de nuestra lista:

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

En este caso, es crucial asegurarse de que el entorno de prueba esté configurado correctamente antes de ejecutar cada prueba, ya que la lista se modifica durante cada ejecución de prueba.

Si echamos un vistazo a la salida del registro, podemos comprobar que los métodos init y teardown se ejecutaron una vez por prueba:

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

3. @BeforeClass

Cuando queremos ejecutar una operación común costosa antes de cada prueba, es preferible ejecutarla solo una vez antes de ejecutar todas las pruebas usando @BeforeClass . Algunos ejemplos de operaciones costosas comunes son la creación de una conexión de base de datos o el inicio de un servidor.

Creemos una clase de prueba simple que simule la creación de una conexión de base de datos:

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

Tenga en cuenta que estos métodos deben ser estáticos , por lo que se ejecutarán antes de ejecutar las pruebas de la clase.

Como hicimos antes, agreguemos también algunas pruebas simples:

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

Esta vez, si echamos un vistazo a la salida del registro, podemos comprobar que los métodos setup y tearDown se ejecutaron solo una vez:

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

4. @BeforeEach y @BeforeAll

@BeforeEac hy @BeforeAll son los equivalentes JUnit 5 de @Before y @BeforeClass . Estas anotaciones fueron renombradas con nombres más claros para evitar confusiones.

Dupliquemos nuestras clases anteriores usando estas nuevas anotaciones, comenzando con las anotaciones @BeforeEach y @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(); } // ... }

Si comprobamos registros, podemos confirmar que funciona de la misma forma que con los @Before y @After anotaciones:

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

Finalmente, hagamos lo mismo con la otra clase de prueba para ver las anotaciones @BeforeAll y @AfterAll en acción:

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

Y el resultado es el mismo que con la anotación anterior:

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

5. Conclusión

En este artículo, mostramos las diferencias entre las anotaciones @Before , @BeforeClass , @BeforeEach y @BeforeAll en JUnit y cuándo se debe usar cada una de ellas.

Como siempre, el código fuente completo de los ejemplos está disponible en GitHub.