Integrando Inicialização de Dados com o TestContext
Ao concluirmos esta aula, nós:
- Saberemos o que é o Spring Test DbUnit e como ele se integra aos
TestExecutionListeners do Spring Test Framework. - Saberemos como declarar as dependências necessárias no Maven e no Gradle 9.
- Compreenderemos como registrar e combinar
TestExecutionListeners (ou usar omergeMode = MergeMode.MERGE_WITH_DEFAULTS) para inicializar nosso banco de dados em testes de integração.
O Que É o Spring Test DbUnit (e os TestExecutionListeners do Spring)?
O ciclo de vida de um teste de integração no Spring Test Framework é orquestrado por componentes chamados TestExecutionListeners. Eles interceptam cada fase da execução do teste (antes da classe, na injeção de dependências da instância de teste, antes do método de teste transacional e após o método de teste).
O Spring Test DbUnit é a biblioteca que conecta o DbUnit ao ciclo de vida do Spring Test Framework através de um listener dedicado (DbUnitTestExecutionListener), oferecendo três anotações principais:
@DatabaseSetup: Inicializa o banco de dados em um estado conhecido antes da execução do método de teste (de forma análoga à anotação nativa@Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD)do próprio Spring Test).@ExpectedDatabase: Verifica e escreve asserções sobre o conteúdo do banco de dados após a execução do método de teste.@DbUnitConfiguration: Permite customizar o carregador de datasets (DataSetLoader) e a conexão utilizada pelo DbUnit.
Vamos ver primeiro como obter as dependências necessárias no Maven e no Gradle.
Obtendo as Dependências Necessárias
Para integrarmos o DbUnit ao Spring Test Framework, declaramos as dependências dbunit e spring-test-dbunit no nosso script de build.
Se estivermos usando o Maven (pom.xml):
|
|
Se estivermos usando o Gradle 9 (Kotlin DSL — build.gradle.kts), adicionamos na nossa suíte integrationTest (ou em testImplementation):
|
|
Nota sobre
@SqlNativo no Spring Boot 4: Se você optar por usar scripts SQL puros com a anotação@Sqldo Spring Test (org.springframework.test.context.jdbc.Sql), você não precisa adicionar nenhuma dependência extra além dospring-boot-starter-test, pois oSqlScriptsTestExecutionListenerjá vem registrado por padrão no Spring TestContext Framework!
Vamos aprender agora como configurar os TestExecutionListeners na nossa classe de teste de integração.
Configurando os TestExecutionListeners no Spring Test
Normalmente não precisamos nos preocupar com TestExecutionListeners porque o Spring Test Framework registra automaticamente uma lista padrão de listeners (incluindo injeção de dependências, contexto de servlet, transações, scripts @Sql, etc.).
Porém, quando queremos utilizar o Spring Test DbUnit, precisamos registrar o listener adicional DbUnitTestExecutionListener usando a anotação @TestExecutionListeners.
Ao testarmos repositórios ou serviços que acessam o banco de dados, a configuração mínima de listeners que precisamos ter ativa inclui:
DependencyInjectionTestExecutionListener: Realiza a injeção de dependências (@Autowired) e inicialização das instâncias de teste.TransactionalTestExecutionListener: Gerencia as transações de teste que respeitam a anotação@Transactional.DbUnitTestExecutionListener(ouTransactionDbUnitTestExecutionListener): Processa as anotações@DatabaseSetup,@ExpectedDatabasee@DbUnitConfiguration.
Veja como fica a nossa classe de teste FindMessageByIdTest declarando explicitamente esses três listeners:
|
|
Dica Moderna:
MergeMode.MERGE_WITH_DEFAULTS! No Spring Test moderno, você não precisa listar manualmente todos os listeners padrão toda vez que quiser adicionar um novo listener! Basta usar o atributomergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS:
1 2 3 4 5 6 7@SpringBootTest @TestExecutionListeners( value = [DbUnitTestExecutionListener::class], mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS ) @Tag("integrationTest") class FindMessageByIdTestCom
MERGE_WITH_DEFAULTS, o Spring mantém todos os seus listeners nativos (injeção, transações, MockMvc, Spring Security,@Sql, MockBean) e simplesmente adiciona oDbUnitTestExecutionListenerà lista!
(Nota sobre Transações: Caso você observe que dados inseridos pelo @DatabaseSetup não estão visíveis dentro da mesma transação do teste ou vice-versa, você pode substituir DbUnitTestExecutionListener::class por TransactionDbUnitTestExecutionListener::class).
Com o DbUnitTestExecutionListener habilitado na configuração padrão, o DbUnit:
- Obtém conexões com o banco de dados procurando um bean do Spring chamado
dataSourceoudbUnitDatabaseConnection. - Carrega os datasets XML utilizando a classe padrão
FlatXmlDataSetLoader.
Esse é um ótimo começo, mas para podermos utilizar replacement datasets ([null], [empty_string]) e customizar propriedades do DbUnit ou conexões de container via Testcontainers, precisamos avançar para a próxima aula!
Resumo
Esta aula nos ensinou três coisas fundamentais:
- O Spring Test DbUnit integra o DbUnit ao ciclo de vida do Spring Test Framework (
@DatabaseSetup,@ExpectedDatabase,@DbUnitConfiguration), trabalhando lado a lado com o suporte nativo do Spring (@Sql). - Para usar o Spring Test DbUnit, declaramos as dependências
dbunitespring-test-dbunitno escopo de teste de integração. - Habilitamos o Spring Test DbUnit registrando o listener
DbUnitTestExecutionListenercom a anotação@TestExecutionListeners(preferencialmente usandomergeMode = MergeMode.MERGE_WITH_DEFAULTS).