@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll

@Before vs @BeforeClass vs @BeforeEach vs @BeforeAll

1. Introdução

Neste breve tutorial, vamos explicar as diferenças entre as anotações@Before,@BeforeClass,@BeforeEache@BeforeAll na JUnit 4 e 5 - com exemplos práticos de como para usá-los.

Também cobriremos brevemente suas@After anotações complementares.

Vamos começar com o JUnit 4.

2. @Before

Methods annotated with the @Before annotation are executed before each test. Isso é útil quando queremos executar algum código comum antes de executar um teste.

Vejamos um exemplo em que inicializamos uma lista e adicionamos alguns 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 finalize() {
        LOG.info("finalize");
        list.clear();
    }
}

Observe que também adicionamos outro método anotado com@After para limpar a lista após a execução de cada teste.

Depois disso, vamos adicionar alguns testes para verificar o tamanho da nossa 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");
}

Nesse caso,it’s crucial to make sure that test environment is properly set up before running each test, pois a lista é modificada durante cada execução do teste.

Se olharmos a saída do log, podemos verificar se os métodosinitefinalize foram executados uma vez por teste:

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

3. @BeforeClass

Quando queremos executar uma operação comum cara antes de cada teste,it’s preferable to execute it only once before running all tests using @BeforeClass. Alguns exemplos de operações caras comuns são a criação de uma conexão com o banco de dados ou a inicialização de um servidor.

Vamos criar uma classe de teste simples que simula a criação de uma conexão de banco de dados:

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

Observe quethese methods have to be static, então eles serão executados antes de executar os testes da classe.

Como fizemos antes, vamos adicionar alguns testes simples:

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

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

Desta vez, se dermos uma olhada na saída do log, podemos verificar se os métodossetupetearDown foram executados apenas uma vez:

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

4. @BeforeEach e@BeforeAll

@BeforeEach and @BeforeAll are the JUnit 5 equivalents of @Before and @BeforeClass. Essas anotações foram renomeadas com nomes mais claros para evitar confusão.

Vamos duplicar nossas classes anteriores usando essas novas anotações, começando com as anotações@BeforeEache@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();
    }

    // ...
}

Se verificarmos os logs, podemos confirmar que funciona da mesma maneira que com as anotações@Beforee@After:

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

Finalmente, vamos fazer o mesmo com a outra classe de teste para ver as anotações@BeforeAlle@AfterAll em ação:

@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 a saída é a mesma da anotação antiga:

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

5. Conclusão

Neste artigo, mostramos as diferenças entre as anotações@Before,@BeforeClass,@BeforeEache@BeforeAll no JUnit e quando cada uma delas deve ser usada.

Como sempre, o código-fonte completo dos exemplos está disponívelover on GitHub.