Customizando Conexões com @ServiceConnection e Testcontainers
Ao concluirmos esta aula, nós:
- Saberemos como criar um carregador de datasets customizado (
ReplacementDataSetLoader) que nos permite usar replacement datasets ([null]e[empty_string]). - Compreenderemos como alterar a configuração padrão do DbUnit através dos beans
DatabaseConfigBeaneDatabaseDataSourceConnectionFactoryBean. - Saberemos como provisionar um banco de dados PostgreSQL real para nossos testes de integração utilizando Testcontainers 2.0 e a anotação
@ServiceConnectiondo Spring Boot 4.1.
Introdução à Anotação @DbUnitConfiguration
A anotação @DbUnitConfiguration nos permite customizar o comportamento do DbUnitTestExecutionListener. Ela possui quatro atributos principais:
databaseConnection: Define os nomes dos beans do Spring que fornecem conexões de banco de dados para o DbUnit (por padrão, procuradbUnitDatabaseConnectionoudataSource).dataSetLoader: Define a classeDataSetLoaderusada para carregar nossos datasets XML.dataSetLoaderBean: Define o nome de um bean do Spring que implementaDataSetLoader.databaseOperationLookup: Define a classe usada para resolver as operações de banco de dados do DbUnit.
Vamos começar criando nosso carregador customizado (ReplacementDataSetLoader) para suportar marcadores de substituição nos nossos datasets!
Usando Replacement Data Sets ([null] e [empty_string])
Por padrão, o FlatXmlDataSetLoader não substitui strings especiais como [null] por valores null reais no banco de dados. Para habilitarmos esse recurso (além do column sensing que já vem ativo no FlatXmlDataSetLoader), criamos a classe ReplacementDataSetLoader seguindo três passos:
Primeiro, criamos uma classe que estende FlatXmlDataSetLoader:
|
|
Segundo, implementamos um método privado createReplacementDataSet() que envolve o IDataSet carregado em um ReplacementDataSet e configura dois placeholders:
- A string
"[empty_string]"é substituída por uma string vazia (""). - A string
"[null]"é substituída pelo valornull.
|
|
Terceiro, sobrescrevemos o método createDataSet(resource: Resource) chamando super.createDataSet(resource) e passando o resultado para createReplacementDataSet(...):
|
|
Agora configuramos nossa classe de teste de integração para usar o ReplacementDataSetLoader através da anotação @DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader::class):
|
|
Contudo, se o nosso arquivo messages.xml tentar inserir uma string vazia (message_text="[empty_string]") no banco de dados:
|
|
Ao executarmos o teste com a configuração padrão do DbUnit, receberemos a seguinte exceção:
|
|
Vamos resolver esse problema customizando a configuração padrão do DbUnit no contexto de teste!
Modificando a Configuração Padrão do DbUnit (DatabaseConfigBean)
Para alterarmos a configuração interna do DbUnit (e também conectarmos um banco PostgreSQL real via Testcontainers!), criamos uma classe de configuração para os nossos testes de integração (IntegrationTestContext) seguindo três passos:
Primeiro, criamos a classe @TestConfiguration (ou @Configuration) IntegrationTestContext que importa a configuração da aplicação:
|
|
Segundo, declaramos um bean do tipo DatabaseConfigBean e habilitamos a propriedade allowEmptyFields = true (permitindo que o DbUnit insira strings vazias "" em instruções INSERT):
|
|
Terceiro, declaramos o bean dbUnitDatabaseConnection do tipo DatabaseDataSourceConnectionFactoryBean, que recebe o DataSource do Spring e o DatabaseConfigBean recém-criado:
|
|
Como nomeamos o método @Bean exatamente como dbUnitDatabaseConnection, o DbUnitTestExecutionListener o detecta automaticamente sem precisarmos alterar a anotação @DbUnitConfiguration!
Conectando um PostgreSQL Real com Testcontainers 2.0 e @ServiceConnection
No passado, muitos testes de integração usavam bancos em memória como H2 porque subir um PostgreSQL local exigia instalação manual. O problema do H2 é que ele não suporta recursos específicos do PostgreSQL (como tipos JSONB, arrays TEXT[], ILIKE ou sintaxes específicas de sequences).
No Spring Boot 4.1 com Testcontainers 2.0.5, podemos declarar um container PostgreSQLContainer como um @Bean anotado com @ServiceConnection dentro da nossa IntegrationTestContext:
|
|
O que a anotação @ServiceConnection faz automaticamente?
- Ela inicia o container Docker
postgres:17-alpineantes doDataSourceser criado. - Ela descobre dinamicamente a porta mapeada, a URL JDBC, o usuário e a senha do container e autoconfigura o
DataSourcedo Spring Boot sem que você precise escrever@DynamicPropertySourceou configurar URLs JDBC em arquivos.properties! - E como o
dbUnitDatabaseConnectionrecebe esse mesmodataSource, tanto a sua aplicação quanto o DbUnit (e o@Sql) conversam com o mesmo banco PostgreSQL real!
Agora basta referenciarmos IntegrationTestContext::class na nossa classe de teste:
|
|
Resumo
Esta aula nos ensinou quatro conceitos fundamentais:
- A anotação
@DbUnitConfigurationpermite customizar oDbUnitTestExecutionListener. - Para habilitar replacement datasets (
[null],[empty_string]), estendemosFlatXmlDataSetLoadere transformamos oIDataSetcarregado em umReplacementDataSet. - Para alterar propriedades internas do DbUnit (como
allowEmptyFields = true), declaramos os beansDatabaseConfigBeanedbUnitDatabaseConnection(DatabaseDataSourceConnectionFactoryBean). - No Spring Boot 4.1 com Testcontainers 2.0, a anotação
@ServiceConnectionem um método@Beanque retornaPostgreSQLContainerconecta automaticamente oDataSourcede teste ao container Docker real.