Em se falando de testes de software existem vários tipos de teste e cada um com seu objetivo. Falando em objetivos o desse texto é falar sobre uma maneira de escrever testes unitários em Java, fazendo uso do Junit 5 e do Mockito, esta última é uma ferramenta bem útil na hora de testar funcionalidades de forma isolada.
Primeiro ponto: qual é o objetivo de um teste unitário?
São testes que têm como objetivo testar a menor unidade de testes, pode ser uma função, ou melhor, um método em Java por exemplo. A ideia é testar entrada e saída e exceções que podem ser lançadas.
Mas qual é a real vantagem ?
Não dá pra falar que é garantir a nível de software o comportamento esteja adequado, mas sim que um determinado bloco de código esteja funcionando independentemente dos demais.
Mão na massa
Tenho esse repositório no github: https://github.com/mmarcosab/api-sor, é uma api simples em java, vou usar como exemplo aqui.
A primeira coisa a se fazer, é verificar se no pom.xml existem essas dependências:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
Caso não exista, só colocar.
São dependências que auxiliam na execução dos testes unitários, mostrando resultados e erros que eventualmente acontecem.
Também é necessário colocar esses plugins:
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.4</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
.. outros plugins
</plugins>
</build>
O surefire executa a etapa de testes unitários no build do programa e o jacoco mostra um relatório de testes com a cobertura do código.
Com isso ao executar um comando “mvn clean install” é possível executar os testes durante o build.
Agora, em test eu tenho o costume de espelhar os pacotes da aplicação para escrever testes das classes, se liga:
Vou começar a escrever um teste. Se liga nesse trecho de código:
Vou escrever um teste unitário para ele:
Teste simples né? Mas ao rodar uma surpresa aparece e o teste não passa ..
Eu poderia colocar aqui só um código pra funcionar, mas melhor entender o motivo desse null e como resolvê-lo, para isso o Mokito vai ser muito útil.
Primeiro eu coloquei um breakpoint no teste e usei o “Debug” ao invés do “Run”:
Feito isso podemos dar uma olhada nos objetos e olha o pedidoController nulo ..
Olhando a classe que quero testar, ela tem vários objetos que são injetados durante sua execução, exemplo:
Além de injetar esses objetos, devo instanciar a classe PedidoController. Mas a aplicação não vai subir, lembra que quero testar a menor unidade possível?
Poderia subir essa api usando a anotação @SpringBootTest, mas não é o que desejo, escolha minha.
Escolhi criar mocks dos objetos e instanciar a classe que será testada, para isso devo fazer isso aqui:
A anotação @BeforeEach faz com que antes de qualquer teste ser executado o método anotado com ela seja executado, e nesse caso os mocks sejam criados.
Com isso, posso rodar de novo e a conversa muda:
Daora né?
Mas pode ficar melhor, como saber se testou todo o método? Escrevi esse texto sobre jacoco há uns dias e ele mostra como olhar um relatório de testes, se liga:
Não estou testando exceções .. Mas calma, com os mocks a gente pode fazer isso usando isso aqui:
Nessa linha escrevi o seguinte: atire uma exceção do tipo Exception.class quando o método savePedidoSalao() com qualquer parâmetro for executado.
Só rodar o teste e sucesso, depois buildar a aplicação e olhar o relatório de testes:
top né?
Com o Mockito também é possível escrever testes para condições (ifs da vida) fazendo uso do when() entre várias outras coisas, se liga na quantidade de métodos:
Agora veja esse outro trecho de código:
O desafio aqui é escrever um teste que valide os dois retornos, vou começar a validar o retorno 1, se liga:
E o teste passou :
Mas no relatório só o primeiro if foi testado:
O Mockito ajuda a simular que houve um retorno desse get e a segunda condição será executada:
Fiz uso do when() para simular uma condição que fizesse outro trecho do meu código ser executado e o teste passou:
O relatório demonstra isso:
Essa é uma forma muito simples de uso dessas tecnologias, mas existem muitas abordagens para testes unitários em java com Spring Boot como o mockMvc para validar rotas de apis, @SpringBootTest para subir de fato a aplicação durante a execução dos testes. Qual usar? Vai do tempo disponível, da capacidade técnica, criticidade etc ..
Fico por aqui. Vlw. Flw.