Compartilhando Datasets e Builders no Gradle 9
Ao final desta aula, você será capaz de:
- Saber como empacotar e publicar nossos datasets do DbUnit e builders de teste em um repositório Maven utilizando o Gradle.
- Utilizar os datasets do DbUnit e builders publicados a partir de outro módulo Gradle no projeto.
Esta aula assume que:
- Você já compreende por que e como compartilhar fixtures entre módulos em uma arquitetura corporativa (Compartilhando Fixtures Entre Módulos com java-test-fixtures).
- Você sabe escrever testes de integração para aplicações Spring Boot utilizando Kotlin 2.4.21, Gradle 9.8.2, Spring Boot 4.1.2 e JUnit Jupiter 6.0.3.
Obtenha o código-fonte no GitHub
Publicando Nossos Datasets de Teste e Builders em um Repositório Maven
Quando queremos utilizar os mesmos datasets do DbUnit (e seus respectivos builders e constantes de teste) a partir de múltiplos módulos Gradle, o primeiro passo consiste em empacotar e publicar esses recursos em um repositório Maven (seja o repositório local ou um repositório remoto corporativo).
Podemos publicar nossos datasets e builders seguindo estes passos:
Primeiro, precisamos criar um novo projeto ou submódulo Gradle dedicado a conter nossos dados de teste (por exemplo, test-data-sets). Como queremos utilizar o layout de diretórios padrão de um projeto JVM, aplicamos o plugin JVM no arquivo build.gradle.kts.
No Gradle clássico com Groovy DSL, utilizava-se a instrução plugins { id 'java' }. Na stack moderna com Gradle 9.8.2 e Kotlin 2.4.21, configuramos nosso arquivo build.gradle.kts da seguinte forma:
|
|
Segundo, precisamos colocar nossos arquivos de dataset do DbUnit no diretório src/main/resources. Se também estivermos compartilhando builders de dados de teste (padrão Object Mother ou Test Data Builder) e constantes de teste (como IDs ou emails fixos), colocamos essas classes no diretório src/main/kotlin.
Essa organização garante que tanto os arquivos XML de dados quanto as classes Kotlin compiladas sejam empacotados diretamente dentro do arquivo JAR gerado.
A estrutura de diretórios a seguir ilustra como os datasets do DbUnit e os builders são organizados no diretório src/main/ da nossa aplicação de exemplo:
|
|
Nessa estrutura:
- O diretório
resources/com/testwithspring/master/armazena os datasets XML utilizados pelo DbUnit para pré-popular e verificar o estado do banco de dados relacional (como PostgreSQL). - O diretório
kotlin/com/testwithspring/master/contém classes utilitárias, comoUserseTasks, contendo constantes que espelham com precisão as chaves primárias e atributos dos registros XML, além de classes comoTaskTestBuilderpara construir instâncias de domínio em memória.
Terceiro, precisamos garantir que podemos publicar nosso arquivo JAR em um repositório Maven. Podemos fazer isso seguindo estes passos:
- Aplicamos o plugin
maven-publish(e opcionalmentejava-test-fixturesse quisermos suporte nativo a variantes de teste no Gradle). O pluginmaven-publishfornece as tarefas necessárias para publicar artefatos de compilação em repositórios no formato Maven. - Configuramos o
groupId,artifactIdeversiondo arquivo JAR publicado dentro do blocopublishing. Além disso, indicamos que a publicação deve empacotar os componentes gerados pelo plugin JVM (from(components["java"])).
Depois de realizarmos as alterações necessárias no nosso arquivo build.gradle.kts, ele se parece com o seguinte:
|
|
Quarto, precisamos publicar nosso arquivo JAR no repositório Maven. Como este é um exemplo prático local, publicaremos nosso arquivo JAR no nosso repositório Maven local (~/.m2/repository). Podemos realizar essa publicação executando o seguinte comando no terminal:
|
|
Nota: Se você estiver trabalhando em um projeto de software corporativo no mundo real, você deve publicar o arquivo JAR em um repositório Maven privado (como Nexus, Artifactory, AWS CodeArtifact ou GitHub Packages) acessível pela infraestrutura da sua organização. O benefício dessa abordagem é que você não precisa executar
publishToMavenLocalmanualmente na máquina de cada desenvolvedor toda vez que alguém fizer alterações nos dados de teste ou builders. Em vez disso, basta atualizar o número da versão da dependência nos módulos consumidores.Leituras Adicionais:
A seguir, veremos como podemos utilizar nossos datasets do DbUnit e builders a partir de outro módulo Gradle consumidor.
Utilizando Nossos Datasets de Teste e Builders a Partir de Outro Módulo Gradle
Quando queremos utilizar nossos datasets do DbUnit e builders compartilhados a partir de outro módulo Gradle, devemos seguir estes passos:
Primeiro, precisamos garantir que o Gradle consulte o repositório Maven local (ou o repositório remoto corporativo) ao resolver as dependências do nosso build. Podemos fazer isso adicionando o repositório correspondente ao bloco repositories no arquivo build.gradle.kts:
|
|
Segundo, precisamos garantir que nossos datasets do DbUnit e builders estejam disponíveis no classpath de execução dos nossos testes.
No Gradle clássico com Groovy DSL, costumava-se configurar a dependência na configuração legada integrationTestRuntimeOnly('com.testwithspring.master:test-data-sets:0.1').
Na stack moderna com Gradle 9.8.2 (Kotlin DSL), podemos declarar a dependência de duas formas, dependendo de como estruturamos a suíte de testes:
- Configuração padrão de dependências de teste:
|
|
- Configuração com a moderna API de JVM Test Suites do Gradle 9:
|
|
Diferença entre escopos: Se o módulo
test-data-setscontiver apenas arquivos XML/YAML estáticos consumidos pelo DbUnit via caminho de recurso (resource path), a configuraçãotestRuntimeOnlyé suficiente. No entanto, como também compartilhamos classes de teste (como builders fluentes e objetos com constantes de teste), devemos utilizartestImplementation(ouimplementationdentro doJvmTestSuite), permitindo que essas classes sejam importadas e compiladas no código dos nossos testes.
Terceiro, como os datasets compartilhados do DbUnit e as classes auxiliares são encontrados diretamente no classpath de testes, podemos utilizá-los exatamente da mesma forma que utilizaríamos datasets e builders locais.
Por exemplo, vamos configurar os dados de teste utilizados por um teste de integração que valida se o objeto TaskRepository funciona conforme o esperado ao criar uma nova tarefa. Depois de configurarmos os dados de teste utilizando Spring Boot 4.1.2, Kotlin 2.4.21 e JUnit Jupiter 6.0.3, o código-fonte da nossa classe de teste se parece com o seguinte:
|
|
Observe que:
- Os arquivos
/com/testwithspring/master/users.xmle/com/testwithspring/master/no-tasks-and-tags.xmlsão carregados da raiz do classpath, onde foram colocados pelo artefato JAR compartilhado. - A constante
Users.JOHN_DOE_IDé importada diretamente da biblioteca compartilhadatest-data-sets, garantindo que o ID do usuário utilizado no teste corresponda com absoluta fidelidade ao registro inserido no banco de dados pelo dataset XML. - Se quisermos instanciar modelos de teste complexos, podemos também usar builders fluentes importados da biblioteca de fixtures compartilhada:
|
|
Boas Práticas ao Compartilhar Datasets e Builders no Gradle
Para garantir que a manutenção de testes distribuídos entre múltiplos módulos permaneça simples e previsível, adote as seguintes práticas recomendadas:
- Versionamento Semântico Rigoroso: Toda vez que você alterar um dataset ou um builder no módulo de dados de teste, incremente o número da versão (por exemplo, de
0.1para0.2ou1.0.0). Isso impede que modificações nos dados de teste quebrem inesperadamente testes em outros módulos que ainda dependem do estado anterior. - Co-localização de Constantes e Builders: Mantenha as constantes de IDs (
Users.JOHN_DOE_ID,Tasks.TASK_ID) e classes builders no mesmo módulo que contém os arquivos XML do DbUnit. Colocá-las emsrc/main/kotlingarante que alterações em campos do schema sejam atualizadas simultaneamente no XML e no código Kotlin em um único commit. - Sincronização com as Migrações de Banco de Dados: A evolução dos datasets deve acompanhar as migrações estruturais do banco de dados (gerenciadas pelo Flyway ou Liquibase). Se uma nova coluna obrigatória for adicionada a uma tabela, atualize os datasets XML correspondentes imediatamente.
- Alinhamento de Versão: Inclua o identificador da versão do modelo de dados no artefato de dados de teste (por exemplo,
test-data-sets:2.1.0), tornando explícito qual versão de schema do banco de dados aquele conjunto de dados reflete. - Não Poluir Datasets Compartilhados: Datasets compartilhados devem conter apenas dados canônicos e comuns a vários módulos. Cenários ou casos de borda específicos de um único módulo devem ser mantidos como datasets locais dentro do diretório
src/test/resourcesdo respectivo módulo consumidor. - Aproveitamento de Recursos do Gradle 9: Em repositórios multi-módulo gerenciados em monorepo, utilize a convenção
java-test-fixtures(testImplementation(testFixtures(project(":core")))) para compartilhamento rápido sem necessidade de publicar emmavenLocal(), reservando a publicação viamaven-publishpara projetos distribuídos entre repositórios git separados.
Resumo
Nesta aula, aprendemos que:
- Podemos publicar nossos artefatos de dados de teste (datasets XML, builders e constantes em Kotlin) em um repositório Maven utilizando o plugin
maven-publishno Gradle 9.8.2. - Como os datasets e builders compartilhados são empacotados em um arquivo JAR e adicionados ao classpath de testes do módulo consumidor, podemos utilizá-los com as anotações do DbUnit (
@DatabaseSetup,@ExpectedDatabase) exatamente como se fossem arquivos locais. - No ecossistema moderno do Gradle 9, a combinação de
build.gradle.kts,JvmTestSuiteejava-test-fixturesoferece flexibilidade tanto para publicação externa em repositórios corporativos quanto para consumo direto em monorepos.