Criando um CRUD de Usuário com Spring Boot Usando TDD: Guia Passo a Passo

Neste tutorial, vamos criar um aplicativo Spring Boot que permite realizar as operações básicas de CRUD (Create, Read, Update, Delete) para gerenciar informações de um usuário, mas seguindo a metodologia TDD. Ou seja, vamos escrever os testes primeiro e depois implementar as funcionalidades. Usaremos o JUnit 5 para os testes e o Mockito para simular dependências, garantindo que o código esteja funcionando corretamente antes de ser implementado.


Preparando o Ambiente

Requisitos

Antes de começarmos, é necessário garantir que temos o ambiente adequado configurado:

  • Java: Instale o JDK 11 ou superior.
  • IDE: Recomendo usar o Spring Tool Suite (STS), mas você pode usar qualquer IDE de sua escolha.
  • Maven: Spring Boot já inclui o Maven, mas você pode instalá-lo separadamente.
  • Banco de Dados: Instale o MySQL ou qualquer outro banco de dados relacional de sua preferência.

Dependências Necessárias

  1. JUnit 5 para testes.
  2. Mockito para simular objetos e dependências.
  3. Spring Boot Test para realizar os testes de integração.

No arquivo pom.xml, adicione as dependências de testes:

<dependencies>
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

Estrutura do Projeto

O projeto terá a seguinte estrutura:

  • src/main/java/com/exemplo/crudusuario: Código-fonte da aplicação.
    • Controller: Controlador REST.
    • Service: Lógica de negócios.
    • Model: Entidade de Usuário.
    • Repository: Repositório JPA.
  • src/test/java/com/exemplo/crudusuario: Testes de unidade e integração.
    • Controller: Testes do controlador.
    • Service: Testes do serviço.

Passo 1: Escrevendo o Primeiro Teste – Testando a Criação de um Usuário

Comece criando o teste para a criação de um novo usuário. Vamos escrever o teste antes de criar o código da funcionalidade.

Teste de Criação de Usuário

No diretório de testes, crie um arquivo chamado UsuarioServiceTest.java.

package com.exemplo.crudusuario;

import com.exemplo.crudusuario.model.Usuario;
import com.exemplo.crudusuario.repository.UsuarioRepository;
import com.exemplo.crudusuario.service.UsuarioService;
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 static org.mockito.Mockito.*;

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

class UsuarioServiceTest {

@InjectMocks
private UsuarioService usuarioService;

@Mock
private UsuarioRepository usuarioRepository;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}

@Test
void testCriarUsuario() {
// Criar um objeto de teste
Usuario usuario = new Usuario();
usuario.setNome("João Silva");
usuario.setEmail("joao@exemplo.com");
usuario.setSenha("senha123");

// Simular o comportamento do repositório
when(usuarioRepository.save(any(Usuario.class))).thenReturn(usuario);

// Chamar o método a ser testado
Usuario usuarioCriado = usuarioService.salvarUsuario(usuario);

// Verificar os resultados
assertNotNull(usuarioCriado);
assertEquals("João Silva", usuarioCriado.getNome());
assertEquals("joao@exemplo.com", usuarioCriado.getEmail());
assertEquals("senha123", usuarioCriado.getSenha());

// Verificar se o repositório foi chamado
verify(usuarioRepository, times(1)).save(usuario);
}
}

Explicação do Teste:

  • @Mock: Usamos o Mockito para simular o comportamento do repositório.
  • @InjectMocks: Spring irá injetar o serviço UsuarioService, onde vamos usar o repositório simulado.
  • when(…).thenReturn(…): Simula a resposta do repositório quando o método save() for chamado.
  • verify(…, times(1)): Verifica se o repositório foi chamado uma vez.

Passo 2: Implementando o Serviço de Usuário

Agora que temos o teste para a criação de um usuário, podemos implementar a classe UsuarioService.

Classe UsuarioService

package com.exemplo.crudusuario.service;

import com.exemplo.crudusuario.model.Usuario;
import com.exemplo.crudusuario.repository.UsuarioRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UsuarioService {

@Autowired
private UsuarioRepository usuarioRepository;

public Usuario salvarUsuario(Usuario usuario) {
return usuarioRepository.save(usuario);
}

public List<Usuario> listarUsuarios() {
return usuarioRepository.findAll();
}

public Usuario obterUsuarioPorId(Long id) {
return usuarioRepository.findById(id).orElse(null);
}

public void excluirUsuario(Long id) {
usuarioRepository.deleteById(id);
}
}

Passo 3: Escrevendo os Testes para o Controlador

Agora vamos escrever os testes para o controlador, que expõe as APIs REST.

Teste do Controlador de Usuário

Crie um arquivo chamado UsuarioControllerTest.java no diretório de testes.

package com.exemplo.crudusuario;

import com.exemplo.crudusuario.controller.UsuarioController;
import com.exemplo.crudusuario.model.Usuario;
import com.exemplo.crudusuario.service.UsuarioService;
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 org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

class UsuarioControllerTest {

private MockMvc mockMvc;

@InjectMocks
private UsuarioController usuarioController;

@Mock
private UsuarioService usuarioService;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(usuarioController).build();
}

@Test
void testCriarUsuario() throws Exception {
// Criar um objeto de teste
Usuario usuario = new Usuario();
usuario.setNome("João Silva");
usuario.setEmail("joao@exemplo.com");
usuario.setSenha("senha123");

// Simular o comportamento do serviço
when(usuarioService.salvarUsuario(any(Usuario.class))).thenReturn(usuario);

// Realizar a requisição POST
mockMvc.perform(post("/usuarios")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"nome\":\"João Silva\", \"email\":\"joao@exemplo.com\", \"senha\":\"senha123\"}"))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.nome").value("João Silva"))
.andExpect(jsonPath("$.email").value("joao@exemplo.com"));
}
}

Explicação do Teste:

  • MockMvc: Utilizado para simular uma requisição HTTP.
  • when(…).thenReturn(…): Simula o retorno do serviço.
  • jsonPath(…): Verifica se o JSON retornado contém os valores esperados.

Passo 4: Implementando o Controlador

Agora que temos os testes, podemos implementar o controlador para expor a API REST.

Classe UsuarioController

package com.exemplo.crudusuario.controller;

import com.exemplo.crudusuario.model.Usuario;
import com.exemplo.crudusuario.service.UsuarioService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/usuarios")
public class UsuarioController {

@Autowired
private UsuarioService usuarioService;

@PostMapping
public ResponseEntity<Usuario> criarUsuario(@RequestBody Usuario usuario) {
Usuario savedUsuario = usuarioService.salvarUsuario(usuario);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUsuario);
}

@GetMapping
public List<Usuario> listarUsuarios() {
return usuarioService.listarUsuarios();
}

@GetMapping("/{id}")
public ResponseEntity<Usuario> obterUsuario(@PathVariable Long id) {
Usuario usuario = usuarioService.obterUsuarioPorId(id);
return usuario != null ? ResponseEntity.ok(usuario) : ResponseEntity.notFound().build();
}

@PutMapping("/{id}")
public ResponseEntity<Usuario> atualizarUsuario(@PathVariable Long id, @RequestBody Usuario usuario) {
usuario.setId(id);
Usuario updatedUsuario = usuarioService.salvarUsuario(usuario);
return ResponseEntity.ok(updatedUsuario);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> excluirUsuario(@PathVariable Long id) {
usuarioService.excluirUsuario(id);
return ResponseEntity.noContent().build();
}
}

Passo 5: Rodando os Testes

Agora que todas as classes e testes estão implementados, basta rodar os testes com o comando:

mvn test

Conclusão

Neste tutorial, aprendemos como criar um CRUD de usuários utilizando Spring Boot e a abordagem TDD (Test-Driven Development). Escrevemos os testes antes da implementação das funcionalidades, garantindo que o código seja testável e de alta qualidade.

Com isso, você agora pode aplicar TDD em seus projetos Spring Boot para garantir que seu código seja confiável desde o início!


Comentários

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *