Migrando da JUnit 4 para a JUnit 5
1. Visão geral
Neste artigo, veremos como podemos migrar do JUnit 4 para a versão mais recente do JUnit 5 - com uma visão geral das diferenças entre as duas versões da biblioteca.
Para obter as diretrizes gerais sobre o uso do JUnit 5, consulte nosso artigohere.
2. Vantagens do JUnit 5
Vamos começar com a versão anterior - JUnit 4 tem algumas limitações claras:
-
Toda a estrutura estava contida em uma única biblioteca jar. A biblioteca inteira precisa ser importada, mesmo quando apenas um recurso específico é necessário. In JUnit 5, we get more granularity and can import only what is necessary
-
Um executor de teste só pode executar testes no JUnit 4 por vez (por exemplo, SpringJUnit4ClassRunner ouParameterized). JUnit 5 allows multiple runners to work simultaneously
-
O JUnit 4 nunca avançou além do Java 7, perdendo muitos recursos do Java 8. JUnit 5 makes good use of Java 8 features
A idéia por trás do JUnit 5 era reescrever completamente o JUnit 4 para resolver a maioria dessas desvantagens.
3. Diferenças
O JUnit 4 foi dividido em módulos que compreendem o JUnit 5:
-
JUnit Platform – este módulo analisa todas as estruturas de extensão em que podemos estar interessados na execução de teste, descoberta e relatório
-
JUnit Vintage – este módulo permite compatibilidade com versões anteriores com JUnit 4 ou mesmo JUnit 3
3.1. Anotações
O JUnit 5 vem com alterações importantes em suas anotações. The most important one is that we can no longer use @Test annotation for specifying expectations.
O parâmetroexpected na JUnit 4:
@Test(expected = Exception.class)
public void shouldRaiseAnException() throws Exception {
// ...
}
Agora, podemos usar um métodoassertThrows:
public void shouldRaiseAnException() throws Exception {
Assertions.assertThrows(Exception.class, () -> {
//...
});
}
O atributotimeout na JUnit 4:
@Test(timeout = 1)
public void shouldFailBecauseTimeout() throws InterruptedException {
Thread.sleep(10);
}
Agora, o métodoassertTimeout na JUnit 5:
@Test
public void shouldFailBecauseTimeout() throws InterruptedException {
Assertions.assertTimeout(Duration.ofMillis(1), () -> Thread.sleep(10));
}
Outras anotações que foram alteradas no JUnit 5:
-
A anotação@Before foi renomeada para@BeforeEach
-
A anotação@After foi renomeada para@AfterEach
-
A anotação@BeforeClass foi renomeada para@BeforeAll
-
A anotação@AfterClass foi renomeada para@AfterAll
-
A anotação@Ignore foi renomeada para@Disabled
3.2. Asserções
Agora podemos escrever mensagens de asserção em um lambda no JUnit 5, permitindo que a avaliação lenta ignore a construção de mensagens complexas até que seja necessário:
@Test
public void shouldFailBecauseTheNumbersAreNotEqual_lazyEvaluation() {
Assertions.assertTrue(
2 == 3,
() -> "Numbers " + 2 + " and " + 3 + " are not equal!");
}
Também podemos agrupar asserções no JUnit 5:
@Test
public void shouldAssertAllTheGroup() {
List list = Arrays.asList(1, 2, 4);
Assertions.assertAll("List is not incremental",
() -> Assertions.assertEquals(list.get(0).intValue(), 1),
() -> Assertions.assertEquals(list.get(1).intValue(), 2),
() -> Assertions.assertEquals(list.get(2).intValue(), 3));
}
3.3. Premissas
A nova classeAssumptions agora está emorg.junit.jupiter.api.Assumptions. O JUnit 5 suporta totalmente os métodos de suposições existentes no JUnit 4 e também adiciona um conjunto de novos métodos para permitir a execução de algumas asserções apenas em cenários específicos:
@Test
public void whenEnvironmentIsWeb_thenUrlsShouldStartWithHttp() {
assumingThat("WEB".equals(System.getenv("ENV")),
() -> {
assertTrue("http".startsWith(address));
});
}
3.4. Etiquetagem e filtragem
No JUnit 4, podemos agrupar os testes usando a anotação@Category. Com o JUnit 5, a anotação@Category é substituída pela anotação@Tag:
@Tag("annotations")
@Tag("junit5")
@RunWith(JUnitPlatform.class)
public class AnnotationTestExampleTest {
/*...*/
}
Podemos incluir / excluir tags específicas usandomaven-surefire-plugin:
maven-surefire-plugin
junit5
3.5. Novas anotações para execução de testes
O@RunWith foi usado para integrar o contexto de teste com outras estruturas ou para alterar o fluxo de execução geral nos casos de teste no JUnit 4.
Com o JUnit 5, agora podemos usar a anotação@ExtendWith para fornecer funcionalidade semelhante.
Como exemplo, para usar os recursos do Spring no JUnit 4:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
{"/app-config.xml", "/test-data-access-config.xml"})
public class SpringExtensionTest {
/*...*/
}
Agora, no JUnit 5, é uma extensão simples:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(
{ "/app-config.xml", "/test-data-access-config.xml" })
public class SpringExtensionTest {
/*...*/
}
3.6. Novas anotações de regras de teste
No JUnit 4, as anotações@Rulee @ClassRule foram usadas para adicionar funcionalidade especial aos testes.
Na JUnit 5. podemos reproduzir a mesma lógica usando a anotação@ExtendWith.
Por exemplo, digamos que tenhamos uma regra personalizada no JUnit 4 para gravar rastreamentos de log antes e depois de um teste:
public class TraceUnitTestRule implements TestRule {
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// Before and after an evaluation tracing here
...
}
};
}
}
E nós o implementamos em um conjunto de testes:
@Rule
public TraceUnitTestRule traceRuleTests = new TraceUnitTestRule();
No JUnit 5, podemos escrever o mesmo de uma maneira muito mais intuitiva:
public class TraceUnitExtension implements AfterEachCallback, BeforeEachCallback {
@Override
public void beforeEach(TestExtensionContext context) throws Exception {
// ...
}
@Override
public void afterEach(TestExtensionContext context) throws Exception {
// ...
}
}
Usando as interfacesAfterEachCallback eBeforeEachCallback do JUnit 5 disponíveis no pacoteorg.junit.jupiter.api.extension,, implementamos facilmente esta regra no conjunto de testes:
@RunWith(JUnitPlatform.class)
@ExtendWith(TraceUnitExtension.class)
public class RuleExampleTest {
@Test
public void whenTracingTests() {
/*...*/
}
}
3.7. JUnit 5 Vintage
O JUnit Vintage ajuda na migração dos testes JUnit executando os testes JUnit 3 ou JUnit 4 dentro do contexto JUnit 5.
Podemos usá-lo importando o JUnit Vintage Engine:
org.junit.vintage
junit-vintage-engine
${junit5.vintage.version}
test
4. Conclusão
Como vimos neste artigo, JUnit 5 é uma versão modular e moderna da estrutura JUnit 4. Introduzimos as principais diferenças entre essas duas versões e sugerimos como migrar de uma para outra.
A implementação completa deste tutorial pode ser encontrada emover on GitHub.