Introdução
Os testes de integração são essenciais para garantir que diferentes módulos de uma aplicação Java funcionem corretamente em conjunto. Neste tutorial, vamos explorar como implementar testes de integração em projetos construídos com Spring Boot e JUnit. Você aprenderá a configurar seu ambiente, a estruturar seus testes e a garantir que sua aplicação esteja pronta para produção. Com uma abordagem prática, apresentaremos exemplos claros que permitirão você integrar testes de forma eficaz em seu ciclo de desenvolvimento, proporcionando um código mais robusto e confiável. Este guia é ideal para desenvolvedores que buscam aprimorar suas habilidades em testes automatizados usando tecnologias atuais.
Etapas
Configuração do Ambiente de Desenvolvimento
Para começar, certifique-se de que o JDK (Java Development Kit) e o Maven estão instalados. Verifique as versões instaladas usando os comandos abaixo. Caso não tenha essas ferramentas, siga as instruções nos sites oficiais.
commands# Verificar versões instaladas
java -version
mvn -versionCriação do Projeto Spring Boot
Utilize o Spring Initializr para gerar um novo projeto Spring Boot com as dependências necessárias. Configure o projeto com as opções: Project: Maven, Language: Java, Spring Boot: última versão estável, Packaging: Jar. Adicione as dependências ‘Spring Web’, ‘Spring Data JPA’ e ‘H2 Database’. Baixe e descompacte o projeto em seu diretório de trabalho.
pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>integracao-testes</artifactId> <version>0.0.1-SNAPSHOT</version> <name>integracao-testes</name> <description>Testes de Integração com Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Configuração do Banco de Dados H2
Edite o arquivo `application.properties` para definir as propriedades do H2 e habilitar o console web.
application.propertiesspring.h2.console.enabled=true spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=update
Criação da Entidade `Produto`
Implemente a classe modelo `Produto`, utilizando anotações JPA para mapear a classe à tabela no banco de dados.
Produto.javapackage com.example.integracaotestes.model; import javax.persistence.*; @Entity @Table(name = "produtos") public class Produto { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String nome; @Column(nullable = false) private Double preco; // Getters e Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public Double getPreco() { return preco; } public void setPreco(Double preco) { this.preco = preco; } }
Criação do Repositório `ProdutoRepository`
Implemente a interface `ProdutoRepository`, que estende `JpaRepository` e fornece métodos CRUD.
ProdutoRepository.javapackage com.example.integracaotestes.repository; import com.example.integracaotestes.model.Produto; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface ProdutoRepository extends JpaRepository<Produto, Long> { // Métodos personalizados podem ser definidos aqui }
Implementação do Serviço `ProdutoService`
Crie a classe `ProdutoService`, que contém a lógica de negócios e usa o `ProdutoRepository` para interagir com o banco de dados.
ProdutoService.javapackage com.example.integracaotestes.service; import com.example.integracaotestes.model.Produto; import com.example.integracaotestes.repository.ProdutoRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; @Service public class ProdutoService { @Autowired private ProdutoRepository produtoRepository; public List<Produto> findAll() { return produtoRepository.findAll(); } public Optional<Produto> findById(Long id) { return produtoRepository.findById(id); } public Produto save(Produto produto) { return produtoRepository.save(produto); } public Produto update(Long id, Produto produtoDetails) { Produto produto = produtoRepository.findById(id).orElseThrow(() -> new RuntimeException("Produto não encontrado")); produto.setNome(produtoDetails.getNome()); produto.setPreco(produtoDetails.getPreco()); return produtoRepository.save(produto); } public void deleteById(Long id) { produtoRepository.deleteById(id); } }
Implementação do Controlador `ProdutoController`
Crie a classe `ProdutoController` para expor os endpoints da API, permitindo operações CRUD.
ProdutoController.javapackage com.example.integracaotestes.controller; import com.example.integracaotestes.model.Produto; import com.example.integracaotestes.service.ProdutoService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/api/produtos") public class ProdutoController { @Autowired private ProdutoService produtoService; @GetMapping public List<Produto> getAllProdutos() { return produtoService.findAll(); } @GetMapping("/{id}") public ResponseEntity<Produto> getProdutoById(@PathVariable Long id) { return produtoService.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @PostMapping public Produto createProduto(@RequestBody Produto produto) { return produtoService.save(produto); } @PutMapping("/{id}") public ResponseEntity<Produto> updateProduto(@PathVariable Long id, @RequestBody Produto produtoDetails) { return ResponseEntity.ok(produtoService.update(id, produtoDetails)); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteProduto(@PathVariable Long id) { produtoService.deleteById(id); return ResponseEntity.noContent().build(); } }
Implementação de Testes de Integração
Crie a classe de testes `ProdutoControllerTest` usando o `@SpringBootTest` e `@AutoConfigureMockMvc` para validar os endpoints da API.
ProdutoControllerTest.javapackage com.example.integracaotestes.controller; import com.example.integracaotestes.model.Produto; import com.example.integracaotestes.repository.ProdutoRepository; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import java.util.List; @SpringBootTest @AutoConfigureMockMvc public class ProdutoControllerTest { @Autowired private MockMvc mockMvc; @Autowired private ProdutoRepository produtoRepository; @BeforeEach public void setUp() { produtoRepository.deleteAll(); // Limpa o banco de dados antes de cada teste } @Test public void testCreateProduto() throws Exception { Produto produto = new Produto(); produto.setNome("Produto Teste"); produto.setPreco(10.0); mockMvc.perform(post("/api/produtos") .contentType(MediaType.APPLICATION_JSON) .content(new ObjectMapper().writeValueAsString(produto))) .andExpect(status().isCreated()); } @Test public void testGetAllProdutos() throws Exception { // Adiciona um produto no banco de dados para testar a recuperação produtoRepository.save(produto); mockMvc.perform(get("/api/produtos")) .andExpect(status().isOk()) .andExpect(jsonPath("$.[0].nome").value("Produto Teste")); } }
Executando a Aplicação e Testes
Utilize o Maven para compilar e executar a aplicação. Em seguida, utilize ferramentas como Postman ou cURL para testar os endpoints da API.
commands# Compilar e executar a aplicação
mvn spring-boot:run
# Executar os testes unitários
mvn testcurl_examples# Listar todos os produtos
curl -X GET http://localhost:8080/api/produtos
# Criar um novo produto
curl -X POST -H "Content-Type: application/json" -d '{"nome":"Novo Produto", "preco":99.99}' http://localhost:8080/api/produtos
Conclusão
Neste tutorial, você aprendeu como implementar testes de integração em uma aplicação Java usando Spring Boot, cobrindo desde a configuração do ambiente até a execução de testes automatizados. Através de exemplos práticos, você entendeu como garantir que suas APIs funcionem conforme o esperado em diferentes cenários. Com essas práticas, você pode aumentar a qualidade do seu código, garantindo que todas as partes da sua aplicação interajam corretamente. Essa abordagem não apenas melhora a confiabilidade da sua aplicação, mas também facilita a manutenção futura, à medida que você continua a expandir suas habilidades em desenvolvimento de software.