📚 Pré-requisitos Teóricos: este projeto aplica conceitos ensinados em Especialização em Backend com Java e Spring Boot. Recomendado revisar antes de começar.

🚀 Guia Didático: Testes Unitários e Mockito na Biblioteca de Jogos

Este guia é a continuação do projeto Biblioteca de Jogos (Módulo 5 do nosso plano de expansão). Aqui, vamos aprender a garantir a qualidade do nosso código através de Testes Unitários usando o framework JUnit 5 e a biblioteca de simulação Mockito.


O que vamos aprender?


Passo 1: Adicionando as Dependências no pom.xml

Para começar a testar, precisamos garantir que temos as dependências corretas. Se você usou o Spring Initializr para criar o projeto do Módulo 1, a dependência spring-boot-starter-test já deve estar incluída. Ela traz o JUnit 5 e o Mockito juntos!

Abra o arquivo pom.xml e verifique se este bloco está presente:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Passo 2: Onde ficam os testes?

Por padrão no Maven, o código-fonte fica em src/main/java e os testes ficam em src/test/java. Vamos criar a mesma estrutura de pacotes para os testes para manter a organização.

Crie o arquivo JogoServiceTest.java no seguinte caminho: src/test/java/br/com/bibliotecajogos/service/JogoServiceTest.java


Passo 3: Escrevendo o Primeiro Teste

Vamos testar o método buscarPorId do JogoService. Queremos garantir que, quando o repositório encontra um jogo, o serviço retorna esse jogo corretamente.

package br.com.bibliotecajogos.service;

import br.com.bibliotecajogos.entity.Jogo;
import br.com.bibliotecajogos.repository.JogoRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

public class JogoServiceTest {

    // 1. Cria um "dublê" do repositório. Ele não acessará o banco de dados de verdade.
    @Mock
    private JogoRepository jogoRepository; 

    // 2. Cria uma instância real do serviço e injeta o repositório mockado nele.
    @InjectMocks
    private JogoService jogoService; 

    @BeforeEach
    void setUp() {
        // Inicializa as anotações do Mockito para esta classe de teste
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void deveRetornarJogoQuandoIdExiste() {
        // --- CENÁRIO (Given) ---
        Long idExistente = 1L;
        Jogo jogoEsperado = new Jogo();
        jogoEsperado.setId(idExistente);
        jogoEsperado.setTitulo("Zelda: Ocarina of Time");

        // Ensinamos o Mock: "Quando chamarem findById(1), retorne o jogo do Zelda"
        when(jogoRepository.findById(idExistente)).thenReturn(Optional.of(jogoEsperado));

        // --- AÇÃO (When) ---
        Jogo jogoRetornado = jogoService.buscarPorId(idExistente);

        // --- VERIFICAÇÃO (Then) ---
        // Verificamos se o resultado não é nulo
        assertNotNull(jogoRetornado);
        
        // Verificamos se o título é exatamente o que esperávamos
        assertEquals("Zelda: Ocarina of Time", jogoRetornado.getTitulo());
        
        // Verificamos se o método do repositório foi chamado exatamente 1 vez
        verify(jogoRepository, times(1)).findById(idExistente);
    }
}

Passo 4: Testando o Fluxo de Erro (Id Não Existe)

E se o jogo não existir no banco? O método deve retornar null. Vamos testar esse comportamento para garantir que nosso código lida bem com falhas.

Adicione este método de teste à classe JogoServiceTest:

    @Test
    void deveRetornarNullQuandoIdNaoExiste() {
        // --- CENÁRIO ---
        Long idNaoExiste = 99L;
        
        // Ensinamos o Mock: "Quando buscarem por 99, retorne vazio"
        when(jogoRepository.findById(idNaoExiste)).thenReturn(Optional.empty());

        // --- AÇÃO ---
        Jogo jogoRetornado = jogoService.buscarPorId(idNaoExiste);

        // --- VERIFICAÇÃO ---
        // Esperamos que o retorno seja nulo
        assertNull(jogoRetornado);
        
        // Verificamos se a busca foi feita no repositório
        verify(jogoRepository, times(1)).findById(idNaoExiste);
    }

🎓 Dissecando o Código (Revisão Didática)

  1. @Mock: Esta anotação diz ao Mockito para criar uma “casca” vazia do objeto. Ele tem os mesmos métodos, mas eles não fazem nada a menos que você os ensine. Isso é crucial porque testes unitários não devem tocar no banco de dados.
  2. @InjectMocks: Esta anotação cria a instância da classe que você quer testar e tenta injetar nela todos os mocks que você declarou com @Mock.
  3. when(...).thenReturn(...): É o coração do Mockito. Como o mock não tem comportamento próprio, você precisa dizer a ele o que fazer. É como dar um script para um ator.
  4. assertEquals(esperado, atual): Método do JUnit que compara dois valores. Se forem diferentes, o teste “falha” e avisa o desenvolvedor.
  5. verify(mock, vezes): Garante que uma determinada ação aconteceu. É útil para testar se o fluxo do código passou por onde deveria.

Desafio para o Aluno

Agora que você viu como testar a busca, tente escrever os testes para o método salvar(Jogo jogo) e excluir(Long id). Dica: Para o salvar, você usará when(jogoRepository.save(jogo)).thenReturn(jogo);.

—`

🚀 Como Executar no Laboratório

1. Abra o terminal na pasta deste projeto

No seu editor/IDE, abra a pasta deste projeto (File > Open Folder) ou navegue via terminal:

cd javaweb_jogos_guia_testes

2. Execute a aplicação e os testes

./mvnw spring-boot:run
./mvnw test

[!TIP] Dica para execução a partir da raiz do repositório: Se você abriu o repositório completo no VS Code, basta navegar até a pasta antes de executar: cd proj_aplicacoes_full_stack/projetos/javaweb_jogos_guia_testes