DEV Community

Diego de Sousa Brandão
Diego de Sousa Brandão

Posted on

Explorando Testes Unitários com JUnit 5 e Mockito: Um Exemplo Prático

Testar software é uma etapa crucial no desenvolvimento de aplicações. Testes unitários garantem que partes individuais do código funcionem conforme o esperado. Neste artigo, vamos explorar um exemplo de código que utiliza o framework de testes JUnit 5 e a biblioteca Mockito para testar uma classe chamada PlanetServices.

Entendendo o Código de Teste

O código de teste em questão é responsável por testar os métodos da classe PlanetServices. Essa classe oferece serviços relacionados a planetas, um crud básico: criar, buscar, listar planetas, deletar.

Código fonte da aplicação:

https://github.com/diegoSbrandao/EstudoTestesAutomatizados/blob/main/starwars/src/test/java/br/com/sw/api/domain/PlanetServicesTest.java

Antes da criação dos testes, crie um pacote a parte para criarmos uma classe com duas constantes para usarmos nos testes, exemplo abaixo:

Image description

O teste começa importando várias classes e métodos estáticos de bibliotecas, como org.assertj.core.api.Assertions e org.mockito.Mockito. Essas importações são usadas para fazer asserções nos testes e configurar comportamentos simulados.

Image description

A anotação @ExtendWith(MockitoExtension.class) na classe de teste indica que a extensão Mockito será usada para fornecer suporte a objetos simulados (mocks).

A anotação @InjectMocks é usada para injetar automaticamente os objetos simulados criados com @Mock na classe de teste. No exemplo, a classe PlanetServices será injetada com o mock PlanetRepository.

Testando a Criação de Planetas

Vamos analisar o primeiro teste:

Image description

  1. A configuração when(planetRepository.save(PLANET)).thenReturn(PLANET) diz que, quando o método save do mock planetRepository for chamado com o argumento PLANET, ele deve retornar o próprio PLANET.

  2. A chamada planetServices.create(PLANET) invoca o método create da classe PlanetServices com o objeto PLANET, e o resultado é atribuído à variável sut.

  3. A asserção assertThat(sut).isEqualTo(PLANET) verifica se o objeto retornado é igual ao objeto esperado PLANET.

Testando a Criação de Planetas com Dados Inválidos

O próximo teste aborda um cenário em que a criação de um planeta com dados inválidos leva a uma exceção:

Image description

  1. A configuração when(planetRepository.save(INVALID_PLANET)).thenThrow(RuntimeException.class) instrui o mock planetRepository a lançar uma exceção do tipo RuntimeException quando o método save for chamado com INVALID_PLANET.

  2. A expressão assertThatThrownBy(() -> planetServices.create(INVALID_PLANET)).isInstanceOf(RuntimeException.class) verifica se a chamada ao método create com INVALID_PLANET lança uma exceção do tipo esperado

Buscando um Planeta por ID Existente

O próximo teste lida com a busca de um planeta por um ID existente:

Image description

  1. A configuração when(planetRepository.findById(1L)).thenReturn(Optional.of(PLANET)) diz que, quando o método findById do mock planetRepository for chamado com o argumento 1L, ele deve retornar um Optional contendo o objeto PLANET.

  2. A chamada planetServices.findById(1L) invoca o método findById da classe PlanetServices com o ID 1L. O resultado é atribuído a sut, um Optional de Planet.

  3. As asserções verificam se o Optional não está vazio e se o objeto contido nele é igual a PLANET.

Buscando um Planeta por ID Inexistente

O próximo teste testa a busca de um planeta por um ID que não existe:

Image description

  1. A configuração when(planetRepository.findById(1L)).thenReturn(Optional.empty()) diz que, quando o método findById do mock planetRepository for chamado com o argumento 1L, ele deve retornar um Optional vazio.

  2. A chamada planetServices.findById(1L) invoca o método findById da classe PlanetServices com o ID 1L. O resultado é atribuído a sut, um Optional de Planet.

  3. A asserção verifica se o Optional está vazio.

Buscando um Planeta por Nome Existente

O teste a seguir lida com a busca de um planeta por um nome existente.

Image description

  1. A configuração when(planetRepository.findByName("Tatooine")).thenReturn(Optional.of(PLANET)) instrui o mock planetRepository a retornar um Optional contendo o objeto PLANET quando o método findByName for chamado com o argumento "Tatooine".

  2. A chamada planetServices.findByName("Tatooine") invoca o método findByName da classe PlanetServices com o nome "Tatooine". O resultado é atribuído a sut, um Optional de Planet.

  3. As asserções verificam se o Optional não está vazio e se o objeto contido nele é igual a PLANET.

Buscando um Planeta por Nome Inexistente

Este teste verifica a busca de um planeta por um nome que não existe:

Image description

  1. A configuração when(planetRepository.findByName(name)).thenReturn(Optional.empty()) instrui o mock planetRepository a retornar um Optional vazio quando o método findByName for chamado com o argumento name.

  2. A chamada planetServices.findByName(name) invoca o método findByName da classe PlanetServices com o nome especificado. O resultado é atribuído a sut, um Optional de Planet.

  3. A asserção verifica se o Optional está vazio.

Listando Planetas

Os testes a seguir abordam a listagem de planetas com base em diferentes cenários.

Testando a listagem de todos os planetas:

Image description

  1. Uma lista planets é criada com um planeta PLANET adicionado a ela.

  2. É criado um exemplo de consulta query usando a classe QueryBuilder com base nas propriedades do objeto PLANET.

  3. A configuração
    when(planetRepository.findAll(query)).thenReturn(planets) instrui o mock planetRepository a retornar a lista de planetas quando o método findAll for chamado com a query especificada.

  4. A chamada planetServices.list(PLANET.getTerrain(), PLANET.getClimate()) invoca o método list da classe PlanetServices com os parâmetros de terreno e clima do planeta.

  5. As asserções verificam se a lista retornada não está vazia, se possui um único elemento e se esse elemento é igual ao objeto PLANET.

Testando a listagem vazia de planetas:

Image description

  1. A configuração when(planetRepository.findAll((Example) any())).thenReturn(Collections.emptyList()) instrui o mock planetRepository a retornar uma lista vazia quando o método findAll for chamado com qualquer argumento.

  2. A chamada planetServices.list(PLANET.getTerrain(), PLANET.getClimate()) invoca o método list da classe PlanetServices com os parâmetros de terreno e clima do planeta.

  3. A asserção verifica se a lista retornada está vazia.

Removendo Planetas por ID

Testando a remoção de um planeta com ID existente:

Image description

  1. A expressão assertThatCode(() -> planetServices.deletePlanet(1L)).doesNotThrowAnyException() verifica se a chamada ao método deletePlanet com o ID 1L não lança nenhuma exceção.

Testando a remoção de um planeta com ID inexistente:

Image description

  1. A configuração doThrow(new RuntimeException()).when(planetRepository).deleteById(99L) instrui o mock planetRepository a lançar uma exceção do tipo RuntimeException quando o método deleteById for chamado com o argumento 99L.

  2. A expressão assertThatThrownBy(() -> planetServices.deletePlanet(99L)).isInstanceOf(RuntimeException.class) verifica se a chamada ao método deletePlanet com o ID 99L lança uma exceção do tipo esperado.

Conclusão

Neste artigo, exploramos um conjunto abrangente de testes unitários que cobrem diferentes cenários de uso da classe PlanetServices.

Usando o JUnit 5 e o Mockito, conseguimos testar a criação, busca, listagem e remoção de planetas em um ambiente controlado.

A prática de escrever testes robustos não apenas ajuda a identificar problemas de código, mas também proporciona confiança na qualidade do software produzido.

O uso conjunto do JUnit 5 e do Mockito demonstra como realizar testes eficazes em ambientes de desenvolvimento Java.

Top comments (0)