You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 09:52:48