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

  1. 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 -version

  2. Criaçã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.gradle
    plugins {
        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()
    }

  3. 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.properties
    spring.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

  4. 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.java
    package 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;
        }
    }

  5. Criação do Repositório `ProdutoRepository`

    Implemente a interface `ProdutoRepository`, que estende `JpaRepository` e fornece métodos CRUD.

    ProdutoRepository.java
    package 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
    }

  6. 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.java
    package 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);
        }
    }

  7. Implementação do Controlador `ProdutoController`

    Crie a classe `ProdutoController` para expor os endpoints da API, permitindo operações CRUD.

    ProdutoController.java
    package 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();
        }
    }

  8. 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.groovy
    package 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"
        }
    }

  9. 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 test

    curl_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!

Hashtags

#Java #SpringBoot #Groovy #Spock #TestesUnitários #DesenvolvimentoÁgil