SpringBootTest:为两个PostgreSQL TestContainer配置不同Liquibase方案
为两个PostgreSQL TestContainer配置不同Liquibase方案的Spring Boot集成测试
核心思路
通过手动创建两个独立的数据源和对应的Liquibase实例,分别绑定到不同的PostgreSQL TestContainer,同时禁用Spring Boot默认的Liquibase自动配置,避免共用默认changelog。
1. 确认依赖
确保测试依赖包含TestContainers、PostgreSQL驱动和Liquibase:
<!-- Maven 示例 --> <dependencies> <!-- TestContainers 核心与PostgreSQL支持 --> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <!-- Liquibase --> <dependency> <groupId>org.liquibase</groupId> <artifactId>liquibase-core</artifactId> </dependency> </dependencies>
2. 初始化两个PostgreSQL TestContainer
在测试类中定义两个容器实例,分别指定不同的数据库名:
import org.testcontainers.containers.PostgreSQLContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @SpringBootTest @Testcontainers // 禁用默认Liquibase自动配置,避免冲突 @EnableAutoConfiguration(exclude = LiquibaseAutoConfiguration.class) public class DualDbIntegrationTest { // 第一个容器:对应数据库A,使用Liquibase方案A @Container static PostgreSQLContainer<?> dbContainerA = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("db_a") .withUsername("test_user") .withPassword("test_pass"); // 第二个容器:对应数据库B,使用Liquibase方案B @Container static PostgreSQLContainer<?> dbContainerB = new PostgreSQLContainer<>("postgres:15-alpine") .withDatabaseName("db_b") .withUsername("test_user") .withPassword("test_pass");
3. 配置独立数据源与Liquibase实例
在测试类内部定义静态配置类,创建两个数据源和对应的Liquibase实例,分别指定各自的changelog文件:
import liquibase.integration.spring.SpringLiquibase; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Qualifier; @Configuration static class DualDbConfig { // 数据源A:绑定到第一个测试容器 @Bean("dataSourceA") DataSource dataSourceA() { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName(dbContainerA.getDriverClassName()); ds.setUrl(dbContainerA.getJdbcUrl()); ds.setUsername(dbContainerA.getUsername()); ds.setPassword(dbContainerA.getPassword()); return ds; } // Liquibase实例A:使用changelog-a.xml @Bean SpringLiquibase liquibaseA(@Qualifier("dataSourceA") DataSource dataSourceA) { SpringLiquibase liquibase = new SpringLiquibase(); liquibase.setDataSource(dataSourceA); liquibase.setChangeLog("classpath:db/changelog/changelog-a.xml"); liquibase.setContexts("test"); return liquibase; } // 数据源B:绑定到第二个测试容器 @Bean("dataSourceB") DataSource dataSourceB() { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName(dbContainerB.getDriverClassName()); ds.setUrl(dbContainerB.getJdbcUrl()); ds.setUsername(dbContainerB.getUsername()); ds.setPassword(dbContainerB.getPassword()); return ds; } // Liquibase实例B:使用changelog-b.xml @Bean SpringLiquibase liquibaseB(@Qualifier("dataSourceB") DataSource dataSourceB) { SpringLiquibase liquibase = new SpringLiquibase(); liquibase.setDataSource(dataSourceB); liquibase.setChangeLog("classpath:db/changelog/changelog-b.xml"); liquibase.setContexts("test"); return liquibase; } }
4. 编写测试用例验证
注入两个数据源,分别验证各自的数据库结构是否符合对应的Liquibase changelog:
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jdbc.core.JdbcTemplate; import static org.junit.jupiter.api.Assertions.assertTrue; @Autowired @Qualifier("dataSourceA") DataSource dataSourceA; @Autowired @Qualifier("dataSourceB") DataSource dataSourceB; @Test void verifyDbASchema() { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceA); Boolean tableExists = jdbcTemplate.queryForObject( "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_name = 'expected_table_a')", Boolean.class ); assertTrue(tableExists); } @Test void verifyDbBSchema() { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceB); Boolean tableExists = jdbcTemplate.queryForObject( "SELECT EXISTS(SELECT 1 FROM information_schema.tables WHERE table_name = 'expected_table_b')", Boolean.class ); assertTrue(tableExists); } }
注意事项
- 确保两个Liquibase changelog文件(
changelog-a.xml、changelog-b.xml)放置在src/main/resources/db/changelog/或src/test/resources/db/changelog/目录下,路径与配置一致 - 若使用
application-test.yml,也可以通过spring.liquibase.enabled=false替代@EnableAutoConfiguration(exclude = ...)来禁用默认Liquibase配置 - 使用
@Qualifier明确指定注入的数据源,避免Spring无法区分两个同类型的Bean
内容的提问来源于stack exchange,提问作者Artsiom Zakruzhnyy
相关产品推荐
相关产品推荐

