Introdução
Se você está buscando otimizar seus testes de unidade em projetos Java, o uso do Groovy com Spock pode ser uma solução poderosa e ágil. Neste tutorial, exploraremos como integrar o Spock, um framework de testes baseado em Groovy, em projetos Java, especialmente aqueles construídos com Spring Boot e gerenciados com Gradle. A combinação destas tecnologias facilita a escrita de testes legíveis e concisos, além de promover práticas ágeis que ajudam na entrega contínua de software. Vamos abordar a configuração do ambiente, a criação de uma aplicação Spring Boot, e a incorporação de testes com o Spock, com exemplos práticos que você pode seguir passo a passo.
Etapas
Configuração do Ambiente de Desenvolvimento
Certifique-se de ter o JDK (Java Development Kit) e o Gradle instalados em sua máquina. Verifique as versões instaladas usando os comandos `java -version` e `gradle -version`. Caso não os tenha instalados, siga as instruções oficiais nos sites das respectivas ferramentas.
commands# Verificar versões instaladas
java -version
gradle -versionCriação do Projeto com Spring Boot e Gradle
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**: Gradle, **Language**: Java, **Spring Boot**: última versão estável, **Packaging**: Jar, **Java**: 11 ou superior. Adicione as dependências ‘Spring Web’, ‘Spring Data JPA’ e ‘H2 Database’. Depois, baixe e descompacte o projeto em seu ambiente de trabalho.
build.gradleplugins { id 'org.springframework.boot' version '2.6.2' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.spockframework:spock-core:2.0-M5-groovy-3.0' } test { useJUnitPlatform() }
Configuração do Banco de Dados H2
Edite o arquivo `src/main/resources/application.properties` para definir as propriedades do banco de dados H2 e habilitar o console web para visualização dos dados.
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` que representará os produtos na aplicação. Use anotações JPA para mapear a classe à tabela do banco de dados.
Produto.javapackage com.example.demo.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.demo.repository; import com.example.demo.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 utiliza o `ProdutoRepository` para interagir com o banco de dados.
ProdutoService.javapackage com.example.demo.service; import com.example.demo.model.Produto; import com.example.demo.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.demo.controller; import com.example.demo.model.Produto; import com.example.demo.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 com Spock
Crie a classe de testes `ProdutoServiceSpec` utilizando Spock para validar a lógica de negócios e operações CRUD da aplicação.
ProdutoServiceSpec.groovypackage com.example.demo.service import com.example.demo.model.Produto import com.example.demo.repository.ProdutoRepository import org.springframework.beans.factory.annotation.Autowired import spock.lang.Specification class ProdutoServiceSpec extends Specification { @Autowired ProdutoService produtoService ProdutoRepository produtoRepository def setup() { produtoRepository = Mock(ProdutoRepository) produtoService = new ProdutoService(produtoRepository: produtoRepository) } def "test find all products"() { given: Produto produto1 = new Produto(id: 1, nome: "Produto 1", preco: 10.0) Produto produto2 = new Produto(id: 2, nome: "Produto 2", preco: 20.0) produtoRepository.findAll() >> [produto1, produto2] when: List<Produto> produtos = produtoService.findAll() then: produtos.size() == 2 } def "test save a product"() { given: Produto produto = new Produto(nome: "Produto 1", preco: 10.0) produtoRepository.save(produto) >> produto when: Produto savedProduto = produtoService.save(produto) then: savedProduto.nome == "Produto 1" } }
Executando a Aplicação e Testes
Use o Gradle 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
gradle bootRun
# Executar os testes unitários
gradle 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 integrar o Spock com um projeto Spring Boot, otimizando seus testes de unidade utilizando Groovy. Demos os primeiros passos desde a configuração do ambiente até a criação de uma aplicação funcional e seu respectivo teste. O uso do Spock permite uma expressão clara e concisa na escrita dos testes, favorecendo equipes ágeis que buscam entrega contínua e qualidade no desenvolvimento. Agora você está preparado para aplicar essas práticas em seus próprios projetos Java!