Executando Testes Unitários: Comparativo Maven vs Gradle
Ao concluirmos esta aula, nós:
- Saberemos como executar nossos testes unitários com o Maven (usando o Maven Surefire Plugin com suporte nativo ao JUnit Platform 6).
- Compreenderemos por que devemos categorizar nossos testes utilizando Tags do JUnit 6 (
@Tag) (que substituíram as antigas@Categorydo JUnit 4). - Seremos capazes de executar exclusivamente os testes unitários filtrados pela sua categoria/tag no Maven.
Executando Testes Unitários com o Maven Surefire Plugin
Podemos executar nossos testes unitários em projetos Maven utilizando o Maven Surefire Plugin. A primeira coisa que devemos fazer é configurar o Maven Surefire Plugin na seção build do nosso arquivo pom.xml.
Para utilizar a configuração padrão do plugin em um projeto moderno com JUnit 6 e Kotlin, adicionamos o seguinte trecho à seção build/plugins do nosso arquivo pom.xml:
|
|
[!NOTE] A partir da versão 2.22.0+ (e especialmente na série 3.x), o
maven-surefire-plugindetecta e executa testes no JUnit Platform (JUnit Jupiter 6) automaticamente sem precisar de provedores extras!
Quando utilizamos a configuração padrão, o Maven Surefire Plugin executa todos os métodos de teste encontrados nas classes de teste que cumprem estas duas condições:
- As classes de teste devem estar localizadas no diretório de código-fonte de testes (
src/test/kotlinousrc/test/java). - O nome da classe de teste deve começar ou terminar com a palavra
Test(ou terminar comTests/TestCase).
[!TIP] Se os nossos testes unitários precisarem de arquivos de recursos, como arquivos
.properties,.yml,.sqlou configurações de log (logback-test.xml), devemos colocar esses arquivos dentro do diretóriosrc/test/resources.
Vamos escrever um teste unitário simples que imprime a string "The default configuration" no System.out (println). Após escrevermos esse teste em Kotlin com JUnit 6, o código-fonte da nossa classe DefaultTest fica assim:
|
|
Agora podemos executar nossos testes unitários rodando o seguinte comando no terminal:
|
|
[!NOTE] Se não quisermos limpar (
clean) todo o diretóriotargetdo projeto antes de rodar nossos testes unitários, basta executar o comando:
1mvn test
Quando executamos nossos testes unitários, notamos no console que o Maven descobre e executa nossa classe DefaultTest:
|
|
Se o nosso projeto possuir apenas testes unitários, não precisamos fazer mais nenhuma alteração no nosso arquivo pom.xml. Contudo, em projetos reais, quase sempre escrevemos também testes de integração e testes End-to-End. Isso significa que precisamos encontrar uma maneira de executar nossos testes unitários rápidos sem disparar os testes de integração e End-to-End junto com eles!
Configurando a Categoria (@Tag) dos Nossos Testes Unitários
Por padrão, o Maven não diferencia testes unitários, testes de integração e testes End-to-End: ele simplesmente roda todos os testes encontrados nas classes cujos nomes começam ou terminam com Test. Podemos resolver esse problema usando uma destas duas opções:
- Opção 1: Usar convenções de nomenclatura diferentes no nome das classes de teste para diferenciar testes unitários (
*Test), testes de integração (*ITou*IntegrationTest) e testes End-to-End (*E2ETest). A desvantagem dessa opção é que somos forçados a adicionar um sufixo ou prefixo artificial ao nome de cada classe de teste apenas para agradar a ferramenta de build. - Opção 2: Usar Categorias / Tags do JUnit (
@Categoryno JUnit 4 ou@Tagno JUnit Jupiter 6). A única exigência dessa opção é anotar cada classe de teste com@Tag("unitTest")(ou uma meta-anotação customizada@UnitTest).
A opção número dois é uma escolha muito superior porque:
- Ela não nos força a poluir o nome das nossas classes de teste com prefixos ou sufixos artificiais.
- Ela nos dá a flexibilidade de criar subcategorias específicas e filtrar testes tanto em nível de classe quanto em nível de método individual.
Por exemplo, podemos criar duas tags diferentes para nossos testes de integração: uma para testes de integração rápidos que rodam na máquina local do desenvolvedor, e outra para testes de integração pesados que só rodam no servidor de Integração Contínua (CI).
[!NOTE] Evolução do JUnit 4 (
@Category) para o JUnit 6 (@Tag) Como vimos na aula Arquitetura do JUnit Platform e Test Engines, no JUnit 4 era necessário criar uma interface marcadora vazia (interface UnitTest) e anotar a classe com@Category(UnitTest::class).No JUnit Jupiter 6, o mecanismo
@Categoryfoi substituído pela anotação nativa@Tag("unitTest")— que aceita uma simplesStringe pode ser combinada com meta-anotações em Kotlin!
Vamos demonstrar isso na prática criando uma nova classe de teste chamada CategoryTest (ou TaggedUnitTest). Essa classe contém um teste unitário que imprime a string "The category: UnitTest" no console.
Para manter a mesma segurança de tipos que tínhamos com a interface marcadora do JUnit 4 sem risco de erros de digitação na string da tag, podemos declarar uma constante ou uma meta-anotação @UnitTest:
|
|
E aplicamos @Tag("unitTest") (ou @UnitTest) à nossa classe CategoryTest:
|
|
Depois de criarmos nossa classe de teste e configurarmos sua categoria/tag, precisamos garantir que o Maven Surefire Plugin execute apenas os testes que pertencem à tag unitTest (no JUnit 4 colocávamos o nome completo da interface com.testwithspring.starter.unittests.UnitTest dentro da tag <groups>; no JUnit 6 colocamos o nome da tag unitTest na mesma tag <groups>!).
Após configurarmos a categoria/tag no pom.xml, a configuração do Maven Surefire Plugin fica assim:
|
|
Quando executamos mvn clean test agora, notamos que o Maven executa apenas o teste encontrado na classe CategoryTest (que possui @Tag("unitTest")) e ignora completamente o teste da classe DefaultTest (que não possui a tag):
|
|
Vamos resumir o que aprendemos nesta aula!
Resumo
Nesta aula, aprendemos três pontos fundamentais:
- Podemos executar nossos testes unitários em projetos Maven utilizando o Maven Surefire Plugin.
- Por padrão, o Maven não diferencia testes unitários, testes de integração e testes End-to-End.
- Devemos categorizar nossos testes utilizando
@Tagno JUnit 6 (o substituto moderno de@Categorydo JUnit 4) e configurar o elemento<groups>do Maven Surefire Plugin para executar apenas a categoria desejada.