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

如何用TestContainers替代Wix Embedded MySQL用于JUnit测试?

用TestContainers替换Wix Embedded MySQL配置

之前在JUnit测试中使用Wix Embedded MySQL,但该工具已不再支持最新版本的MySQL,现需切换到TestContainers,以下是替换原配置的具体方案,原配置类代码如下:

@Configuration
 @Profile({"mysql"})
 @ConditionalOnProperty(prefix = "spring", name = "datasource.jdbcUrl")
 public class EmbeddedMySqlDbConfig {

  protected static Logger logger = LoggerFactory.getLogger(EmbeddedMySqlDbConfig.class);

  @Bean(name = "downloadConfig")
  DownloadConfig downloadConfig() {
    String downloadPath = "/app/mysql";
    logger.info("Embedded MySQL download path is {}", downloadPath);
    DownloadConfig config = aDownloadConfig().withCacheDir(downloadPath).build();
    return config;
 }

 @Bean(name = "mysqldConfig")
 MysqldConfig mysqldConfig(@Value("${spring.datasource.username}") String dbUsername,
        @Value("${spring.datasource.password}") String dbPassword, @Value("${mysql.port}") int port) {
    MysqldConfig config = aMysqldConfig(v5_7_latest).withPort(port).withUser(dbUsername, dbPassword).build();
    return config;
 }

  private void addSchema(String databaseName, Builder builder) {
    SchemaConfig schema = aSchemaConfig(databaseName).build();
    builder.addSchema(schema);
  }

 @Bean(name = "embeddedMysql")
  EmbeddedMysql embeddedMysql(@Qualifier("downloadConfig") DownloadConfig downloadConfig,
        @Qualifier("mysqldConfig") MysqldConfig config, @Value("${mysql.databaseName}") String databaseName,
        @Value("${mysql.databaseName1}") String databaseName1) {
     try {
        Builder builder = new Builder(config, downloadConfig);
        for (int i = 0; i < 2; i++) {
            String name = databaseName;
            if (i == 1) {
                name = null;
                if (databaseName1 != null && databaseName1.trim().length() > 0) {
                    name = databaseName1;
                }
            }
            if (name != null) {
                addSchema(name, builder);
            }
         }
        EmbeddedMysql mysql = builder.start();
        logger.info("embedded mysql started");
        return mysql;
     } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        throw e;
     }
 }

 @Bean(name = "dataSource")
 @DependsOn("embeddedMysql")
 public DataSource dataSource(@Value("${spring.datasource.username}") String dbUsername,
        @Value("${spring.datasource.password}") String dbPassword,
        @Value("${spring.datasource.jdbcUrl}") String url,
        @Value("${spring.datasource.driver-class-name}") String driverClassName) {

    DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.driverClassName(driverClassName);
    dataSourceBuilder.url(url);
    dataSourceBuilder.username(dbUsername);
    dataSourceBuilder.password(dbPassword);
    return dataSourceBuilder.build();
 }

 @Bean(name = "requestDataSource")
 @ConditionalOnProperty(prefix = "request", name = "datasource.jdbcUrl")
 @DependsOn("dataSource")
 public DataSource requestDataSource(@Value("${request.datasource.username}") String dbUsername,
        @Value("${spring.datasource.password}") String dbPassword,
        @Value("${request.datasource.jdbcUrl}") String url,
        @Value("${spring.datasource.driver-class-name}") String driverClassName) {
    DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
    dataSourceBuilder.driverClassName(driverClassName);
    dataSourceBuilder.url(url);
    dataSourceBuilder.username(dbUsername);
    dataSourceBuilder.password(dbPassword);
    return dataSourceBuilder.build();
    }
}

替换步骤

1. 添加TestContainers依赖

根据项目构建工具选择对应的依赖:

Maven

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>mysql</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <scope>test</scope>
</dependency>
<!-- Spring Boot整合依赖(可选,简化配置) -->
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>spring-boot</artifactId>
    <scope>test</scope>
    <version>1.19.0</version> <!-- 使用最新稳定版本 -->
</dependency>

Gradle

testImplementation 'org.testcontainers:mysql'
testImplementation 'org.testcontainers:junit-jupiter'
// Spring Boot整合依赖(可选)
testImplementation 'org.testcontainers:spring-boot:1.19.0'

2. 替换原配置类

移除EmbeddedMySqlDbConfig,创建新的TestContainers配置类,实现相同的容器启动、数据库创建及数据源配置逻辑:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.utility.DockerImageName;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Statement;

@Configuration
@Profile({"mysql"})
@ConditionalOnProperty(prefix = "spring", name = "datasource.jdbcUrl")
public class TestcontainersMysqlConfig {

    private static final Logger logger = LoggerFactory.getLogger(TestcontainersMysqlConfig.class);

    @Bean(initMethod = "start", destroyMethod = "stop")
    public MySQLContainer<?> mysqlContainer(
            @Value("${spring.datasource.username}") String dbUsername,
            @Value("${spring.datasource.password}") String dbPassword,
            @Value("${mysql.databaseName}") String databaseName,
            @Value("${mysql.databaseName1}") String databaseName1
    ) {
        // 指定MySQL镜像版本,可替换为需要的版本(如8.0、5.7)
        MySQLContainer<?> container = new MySQLContainer<>(DockerImageName.parse("mysql:8.0"))
                .withUsername(dbUsername)
                .withPassword(dbPassword);

        // 创建配置的数据库
        try (Connection conn = container.createConnection("");
             Statement stmt = conn.createStatement()) {
            stmt.executeUpdate(String.format("CREATE DATABASE IF NOT EXISTS %s", databaseName));
            if (databaseName1 != null && !databaseName1.trim().isEmpty()) {
                stmt.executeUpdate(String.format("CREATE DATABASE IF NOT EXISTS %s", databaseName1));
            }
            logger.info("成功创建数据库:{}、{}", databaseName, databaseName1);
        } catch (Exception e) {
            logger.error("创建数据库失败", e);
            throw new RuntimeException(e);
        }

        logger.info("TestContainers MySQL容器启动完成");
        return container;
    }

    @Bean(name = "dataSource")
    public DataSource dataSource(
            MySQLContainer<?> mysqlContainer,
            @Value("${spring.datasource.username}") String dbUsername,
            @Value("${spring.datasource.password}") String dbPassword,
            @Value("${mysql.databaseName}") String databaseName
    ) {
        // 动态生成目标数据库的JDBC URL
        String jdbcUrl = mysqlContainer.getJdbcUrl().replace("/test", "/" + databaseName);
        return DataSourceBuilder.create()
                .driverClassName(mysqlContainer.getDriverClassName())
                .url(jdbcUrl)
                .username(dbUsername)
                .password(dbPassword)
                .build();
    }

    @Bean(name = "requestDataSource")
    @ConditionalOnProperty(prefix = "request", name = "datasource.jdbcUrl")
    public DataSource requestDataSource(
            MySQLContainer<?> mysqlContainer,
            @Value("${request.datasource.username}") String dbUsername,
            @Value("${spring.datasource.password}") String dbPassword,
            @Value("${mysql.databaseName1}") String databaseName1
    ) {
        String jdbcUrl = mysqlContainer.getJdbcUrl().replace("/test", "/" + databaseName1);
        return DataSourceBuilder.create()
                .driverClassName(mysqlContainer.getDriverClassName())
                .url(jdbcUrl)
                .username(dbUsername)
                .password(dbPassword)
                .build();
    }
}

3. 配置文件调整

  • 移除原配置中的mysql.port项,TestContainers会自动分配随机端口,避免端口冲突。
  • 原配置文件中的spring.datasource.jdbcUrl和request.datasource.jdbcUrl无需硬编码,会由配置类动态生成。

核心差异说明

  • TestContainers基于Docker运行MySQL容器,自动管理镜像拉取、容器启停,无需手动维护MySQL安装包。
  • 数据库创建逻辑通过JDBC直接执行SQL实现,替代原Wix工具的Schema配置。
  • 数据源URL动态生成,适配容器的随机端口,无需担心环境不一致问题。

内容的提问来源于stack exchange,提问作者Shubham Shekhar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:49:51