Modelo de Extensões do JUnit 6 (@ExtendWith e @TempDir)
Ao concluirmos esta aula, nós:
- Saberemos o que era uma Rule (
@Rule) no JUnit 4 e como ela evoluiu para uma Extensão (Extension) no JUnit Jupiter 6. - Seremos capazes de registrar e utilizar extensões do JUnit 6 em nossas classes de teste.
- Seremos capazes de criar arquivos e diretórios temporários que são automaticamente excluídos após a execução de um método de teste utilizando
@TempDir(substituindo a antigaTemporaryFolderrule).
O Que É uma Rule / Extensão no JUnit?
No JUnit, uma Rule (no JUnit 4) ou Extensão (no JUnit Jupiter 6) é um componente que intercepta chamadas de métodos de teste e nos permite executar ações customizadas antes que um método de teste seja iniciado, durante sua resolução de parâmetros e depois que o método de teste tiver terminado sua execução.
No JUnit 4 clássico, todas as rules precisavam implementar a interface org.junit.rules.TestRule. No JUnit Jupiter 6, o conceito de @Rule e @ClassRule foi unificado sob a interface base org.junit.jupiter.api.extension.Extension e suas interfaces de ciclo de vida especializadas (como BeforeEachCallback, AfterEachCallback, ParameterResolver).
Podemos fazer coisas muito úteis com extensões e recursos nativos do JUnit 6. Por exemplo, o JUnit Jupiter fornece mecanismos que podem:
- Criar arquivos e diretórios temporários que são automaticamente limpos e excluídos após a execução de um método de teste (
@TempDir). - Falhar um teste automaticamente se o tempo limite especificado for excedido antes do término do método (
@Timeout). - Configurar um recurso externo, como um socket, servidor HTTP (WireMock) ou contêiner de banco de dados (Testcontainers) antes do teste e liberar o recurso automaticamente ao final.
A seguir, descobriremos como ativar e utilizar extensões em nossas classes de teste.
Utilizando Extensões no JUnit 6 (Substituindo @Rule)
No JUnit 4, para usar uma rule como FooBarRule, éramos obrigados a seguir dois passos burocráticos:
- Adicionar um campo
publicnão-estático na classe de teste cujo tipo fosse subtipo deTestRule. - Anotar esse campo com
@Rule.
|
|
@Rule obrigatoriamente precisava ser public e não podia ser static (caso contrário, exigia @ClassRule). Em Kotlin, como propriedades geram campos privados com getters públicos por padrão, isso exigia o uso da sintaxe @get:Rule ou @JvmField, o que frequentemente confundia desenvolvedores.
No JUnit Jupiter 6, essa limitação desapareceu! Podemos ativar uma extensão de duas formas muito mais limpas:
- Forma Declarativa (
@ExtendWith): Anotamos a classe (ou método) diretamente com@ExtendWith(FooBarExtension::class). - Forma Programática (
@RegisterExtension): Caso precisemos passar parâmetros no construtor da extensão, declaramos uma propriedade na classe anotada com@RegisterExtension(que não precisa serpublic!).
Suponha que queiramos usar a extensão FooBarExtension em nossa classe de teste. Depois de habilitá-la no JUnit 6, o código-fonte da nossa classe fica assim:
|
|
Ou, se precisarmos configurar a instância programaticamente com @RegisterExtension:
|
|
Vamos colocar esse conhecimento em prática e descobrir como podemos criar arquivos e diretórios temporários que são excluídos automaticamente após a execução de um método de teste.
Utilizando a Extensão Nativa @TempDir (Substituindo a TemporaryFolder Rule)
Quando precisamos criar arquivos e/ou diretórios que devem ser excluídos após a execução de um método de teste, o JUnit 4 exigia instanciar a rule TemporaryFolder.
No JUnit Jupiter 6, essa funcionalidade já vem embutida nativamente através da anotação @TempDir (org.junit.jupiter.api.io.TempDir). Para habilitá-la, podemos anotar uma propriedade da classe (lateinit var tmpFolder: Path ou File) ou injetá-la diretamente como parâmetro do método @Test!
Depois de habilitarmos o @TempDir em nossa classe de teste, o código-fonte fica assim:
|
|
Agora podemos criar arquivos e diretórios dentro de tmpFolder. Vamos criar um teste simples que cria um arquivo chamado file.txt que será automaticamente excluído pelo JUnit assim que o método de teste terminar.
Em outras palavras, adicionaremos um novo método de teste à nossa classe implementando estes três passos:
- Criar um novo arquivo
file.txtdentro do diretório temporáriotmpFoldere garantir sua criação no sistema de arquivos (createNewFile()). - Garantir que o objeto
Filecriado é realmente um arquivo (isFile). - Garantir que o arquivo foi criado exatamente dentro do diretório raiz da nossa pasta temporária (
tmpFolder).
Depois de implementarmos este método de teste, o código-fonte completo da nossa classe de teste ficará assim:
|
|
(Dica de Kotlin + NIO.2: Com @TempDir, você também pode usar java.nio.file.Path em vez de java.io.File, o que permite criar o arquivo de forma ainda mais concisa com Files.createFile(tmpDir.resolve("file.txt"))).
Na antiga
TemporaryFolder rule do JUnit 4 (antes da versão 4.13), o JUnit não garantia que uma falha ao deletar os arquivos temporários causaria falha no teste (exigindo configurar manualmente TemporaryFolder.builder().assureDeletion().build()).No JUnit Jupiter 6, o
@TempDir já verifica a exclusão por padrão e permite configurar explicitamente o modo de limpeza (cleanup), por exemplo para manter os arquivos apenas se o teste falhar (ótimo para diagnóstico):
|
|
Vamos resumir o que aprendemos nesta aula.
Resumo
Esta aula nos ensinou quatro pontos essenciais:
- Uma Rule (no JUnit 4) ou Extensão (no JUnit 6) é um componente que intercepta o ciclo de vida dos métodos de teste, permitindo executar lógicas antes e depois de cada teste.
- O JUnit 6 unificou as antigas
@Rulee@ClassRulesob o modelo de extensões com@ExtendWithe@RegisterExtension. - Ao contrário do JUnit 4 (que exigia campos
publicnão-estáticos com@Rule), o JUnit 6 permite injetar extensões declarativamente na classe, em propriedades ou diretamente nos parâmetros do método de teste. - A extensão nativa
@TempDir(substituta da antigaTemporaryFolderrule) permite criar arquivos e diretórios temporários comFileouPathque são automaticamente removidos após a execução do teste.