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

如何创建Quarkus自身应用的测试资源以模拟多节点通信?

在Quarkus中测试多节点HTTP通信的解决方案

核心思路

Quarkus的QuarkusTestResourceLifecycleManager确实可用于管理测试所需的外部资源,包括启动额外的应用实例。但直接调用Quarkus.run()会与测试本身的Quarkus应用实例冲突,正确做法是使用Quarkus的Launcher API启动独立的、指定端口的应用实例。

实现步骤

1. 编写自定义TestResource管理多实例

创建MultiNodeTestResource类,通过Launcher启动指定端口的应用实例,并记录实例的端口与地址信息:

import io.quarkus.bootstrap.app.QuarkusBootstrap;
import io.quarkus.bootstrap.app.QuarkusLauncher;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

public class MultiNodeTestResource implements QuarkusTestResourceLifecycleManager {

    private final CopyOnWriteArrayList<QuarkusLauncher> launchers = new CopyOnWriteArrayList<>();
    private final Map<String, String> config = new HashMap<>();

    @Override
    public Map<String, String> start() {
        // 启动第一个实例,端口8082
        launchInstance(8082, "node1");
        // 启动第二个实例,端口8083
        launchInstance(8083, "node2");

        return config;
    }

    private void launchInstance(int port, String nodeName) {
        try {
            QuarkusBootstrap bootstrap = QuarkusBootstrap.builder()
                    .setApplicationRoot(QuarkusBootstrap.DefaultApplicationRoot.builder()
                            .addModuleClassPathElement(Thread.currentThread().getContextClassLoader())
                            .build())
                    .setArguments("-Dquarkus.http.port=" + port)
                    .build();

            QuarkusLauncher launcher = bootstrap.createLauncher();
            launcher.start();
            launchers.add(launcher);

            config.put(nodeName + ".port", String.valueOf(port));
            config.put(nodeName + ".url", "http://localhost:" + port);
        } catch (Exception e) {
            throw new RuntimeException("Failed to launch Quarkus instance", e);
        }
    }

    @Override
    public void stop() {
        // 停止所有启动的实例
        for (QuarkusLauncher launcher : launchers) {
            try {
                launcher.stop();
            } catch (Exception e) {
                // 忽略停止时的异常,避免影响测试结束
            }
        }
    }
}

2. 在测试类中使用该TestResource

通过@TestResource注解引入自定义资源,再通过@ConfigProperty获取各个节点的地址,编写节点间通信测试:

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.junit.jupiter.api.Test;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

@QuarkusTest
@TestResource(MultiNodeTestResource.class)
public class MultiNodeCommunicationTest {

    @Inject
    @ConfigProperty(name = "node1.url")
    String node1Url;

    @Inject
    @ConfigProperty(name = "node2.url")
    String node2Url;

    private final HttpClient httpClient = HttpClient.newHttpClient();

    @Test
    void testNodeToNodeCommunication() throws Exception {
        // 测试node1向node2发送请求
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(node2Url + "/some-endpoint"))
                .GET()
                .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        // 断言响应符合预期
        assert response.statusCode() == 200;
    }
}

关键注意事项

  • 端口冲突:若需动态避免端口冲突,可使用SocketUtils.findAvailableTcpPort()获取可用端口后传递给实例。
  • 资源清理:必须在stop()方法中停止所有启动的实例,避免测试后残留进程。
  • 类路径配置:确保QuarkusBootstrap正确设置应用类路径,否则启动的实例可能无法找到应用代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 20:12:41