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

如何在Quarkus中结合Testcontainers使用并实现依赖注入?

在Quarkus中结合Testcontainers与依赖注入的正确姿势

你遇到的问题核心原因很明确:单纯使用@Testcontainers注解并不会启动Quarkus的依赖注入(DI)容器,只有@QuarkusTest注解会触发Quarkus测试上下文的初始化,包括DI容器、配置加载等核心功能。只要保留@QuarkusTest,再配合Testcontainers的配置,就能解决注入为空的问题。

下面是两种可行的实现方式:

方式一:同时使用@QuarkusTest和@Testcontainers

直接在测试类上同时添加两个注解,通过系统属性覆盖Quarkus的数据库配置,让应用连接到Testcontainers启动的MariaDB实例:

import io.quarkus.test.junit.QuarkusTest;
import org.testcontainers.containers.MariaDBContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@QuarkusTest
@Testcontainers
public class TeamServiceTest {

    // static修饰保证容器在测试类生命周期内只启动一次
    @Container
    private static final MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.6")
            .withDatabaseName("testdb")
            .withUsername("testuser")
            .withPassword("testpass");

    static {
        // 在Quarkus启动前覆盖数据库配置,确保应用连接到Testcontainers容器
        System.setProperty("quarkus.datasource.jdbc.url", mariaDBContainer.getJdbcUrl());
        System.setProperty("quarkus.datasource.username", mariaDBContainer.getUsername());
        System.setProperty("quarkus.datasource.password", mariaDBContainer.getPassword());
    }

    @Inject
    TeamService teamService;

    @Test
    void verifyTeamServiceInjection() {
        assertNotNull(teamService, "TeamService 注入失败");
        // 这里添加你的业务测试逻辑
    }
}

方式二:使用QuarkusTestResource(更优雅的配置方式)

如果想把容器管理和配置逻辑从测试类中抽离,可以自定义QuarkusTestResource实现类,这种方式更符合单一职责原则:

第一步:编写自定义TestResource类

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.testcontainers.containers.MariaDBContainer;
import java.util.Map;

public class MariaDBTestResource implements QuarkusTestResourceLifecycleManager {

    private MariaDBContainer<?> mariaDBContainer;

    @Override
    public Map<String, String> start() {
        // 启动MariaDB容器
        mariaDBContainer = new MariaDBContainer<>("mariadb:10.6")
                .withDatabaseName("testdb")
                .withUsername("testuser")
                .withPassword("testpass");
        mariaDBContainer.start();
        
        // 返回需要覆盖的Quarkus配置
        return Map.of(
                "quarkus.datasource.jdbc.url", mariaDBContainer.getJdbcUrl(),
                "quarkus.datasource.username", mariaDBContainer.getUsername(),
                "quarkus.datasource.password", mariaDBContainer.getPassword()
        );
    }

    @Override
    public void stop() {
        // 测试结束后停止容器
        if (mariaDBContainer != null) {
            mariaDBContainer.stop();
        }
    }
}

第二步:在测试类中使用该TestResource

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.common.QuarkusTestResource;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@QuarkusTest
@QuarkusTestResource(MariaDBTestResource.class)
public class TeamServiceTest {

    @Inject
    TeamService teamService;

    @Test
    void verifyTeamServiceInjection() {
        assertNotNull(teamService);
        // 添加业务测试逻辑
    }
}

关键注意事项

  1. 必须保留@QuarkusTest:这个注解是Quarkus测试上下文的入口,没有它,DI容器不会初始化,@Inject的对象必然为空。
  2. 容器生命周期管理:使用static修饰容器实例(方式一)或通过TestResource(方式二),避免每个测试方法都重新启动容器,提升测试效率。
  3. 配置时机:确保数据库配置在Quarkus启动前被覆盖,这样应用才能正确连接到Testcontainers启动的数据库实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:20:30