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

Spring Boot集成Test Containers测试失败:UnknownHostException(app_db)

问题:TestContainers集成测试连接app_db失败(UnknownHostException)

我基于Spring Boot + MySQL + Docker + Flyway实现了一个项目,使用Test Containers编写集成测试类时,程序始终尝试连接docker-compose中定义的app_db主机,抛出java.net.UnknownHostException: No such host is known (app_db)异常。以下是相关代码和配置:

测试类代码

@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class UserControllerIntegrationTest {

    @Autowired
    private UserController userController;

    @Autowired
    UriComponentsBuilder builder;

    @Container
    public static MySQLContainer container = new MySQLContainer("mysql:latest")
            .withDatabaseName("example_db")
            .withUsername("Test")
            .withPassword("Test");

    @Container
    public static GenericContainer<?> redis =
            new GenericContainer<>(DockerImageName.parse("redis:6.2-alpine")).withExposedPorts(6379);

    @BeforeAll
    public static void setUp(){
        container.withReuse(true);
        container.withInitScript("src/main/test/resources/schema.sql");
        container.start();
        redis.start();
    }

    @DynamicPropertySource
    public static void overrideProperties(DynamicPropertyRegistry registry){
        registry.add("spring.datasource.url", container::getJdbcUrl);
        registry.add("spring.datasource.username", container::getUsername);
        registry.add("spring.datasource.password", container::getPassword);
        registry.add("spring.datasource.driver-class-name", container::getDriverClassName);
    }

    @Test
    public void testCreateUser(){
        CreateUserRequestDto request = new CreateUserRequestDto();
        request.setName("Test User");
        request.setAge(45);
        UserResponseDto response = userController.create(request);
        assertNotNull(response);
    }

}

docker-compose.yml配置

version: "3.0"
 services:
  api_service:
    build: .
    restart: always
    ports:
      - 8090:8090
    depends_on:
      - mysql_db
    links:
      - mysql_db:app_db
  mysql_db:
    image: "mysql:8.0"
    restart: always
    ports:
      - 3306:3306
    environment:
      MYSQL_DATABASE: test_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: password

application.yml配置

app:
  name: test-service

server:
  port: 8090

spring:
  datasource:
    url: jdbc:mysql://app_db:3306/test_db
    username: user
    password: password
    initialization-mode: always
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
    hibernate:
      ddl-auto: create

报错信息

Caused by: java.net.UnknownHostException: No such host is known (app_db)

解决方法

核心原因

测试代码中虽然通过@DynamicPropertySource尝试覆盖数据源配置,但因容器生命周期管理错误、配置加载顺序冲突,导致application.yml中app_db的原始配置未被正确覆盖,程序仍尝试连接docker-compose专属的内部主机名。

具体修复步骤

1. 修正TestContainers容器初始化逻辑

@Testcontainers注解会自动管理容器的启动/停止,手动调用start()会导致重复初始化,干扰动态属性注入:

  • 删除@BeforeAll方法,移除手动启动容器的代码
  • 将withReuse(true)和withInitScript直接放在容器实例化时配置,同时用classpath路径替代绝对路径,提高兼容性:
    @Container
    public static MySQLContainer container = new MySQLContainer("mysql:latest")
            .withDatabaseName("example_db")
            .withUsername("Test")
            .withPassword("Test")
            .withReuse(true)
            .withInitScript("classpath:schema.sql");
    
    @Container
    public static GenericContainer<?> redis =
            new GenericContainer<>(DockerImageName.parse("redis:6.2-alpine"))
                    .withExposedPorts(6379);
    

2. 补全动态属性覆盖(含Flyway)

如果项目使用Flyway,它会独立读取数据源配置,需要一起覆盖:

@DynamicPropertySource
public static void overrideProperties(DynamicPropertyRegistry registry){
    registry.add("spring.datasource.url", container::getJdbcUrl);
    registry.add("spring.datasource.username", container::getUsername);
    registry.add("spring.datasource.password", container::getPassword);
    registry.add("spring.datasource.driver-class-name", container::getDriverClassName);
    // 覆盖Flyway配置(如果使用了Flyway)
    registry.add("spring.flyway.url", container::getJdbcUrl);
    registry.add("spring.flyway.user", container::getUsername);
    registry.add("spring.flyway.password", container::getPassword);
    // 覆盖Redis配置(如果需要使用Redis)
    registry.add("spring.redis.host", redis::getHost);
    registry.add("spring.redis.port", redis::getFirstMappedPort);
}

3. 为测试环境单独配置

创建src/test/resources/application-test.yml,隔离测试与生产配置:

spring:
  datasource:
    initialization-mode: never # 禁用默认初始化,改用TestContainers的initScript
  jpa:
    hibernate:
      ddl-auto: none # 避免与Flyway的Schema管理冲突
  flyway:
    enabled: true # 按需开启

然后在测试类上添加@ActiveProfiles("test"),指定使用测试配置:

@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@ActiveProfiles("test") // 添加该注解
public class UserControllerIntegrationTest {
    // ... 其他代码
}

4. 验证Docker运行状态

确保本地Docker daemon处于运行状态,TestContainers能正常创建和管理容器。


内容的提问来源于stack exchange,提问作者Lakshitha Gihan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 20:00:58