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

基于Jetty+Jersey应用与Nebula Graph的集成测试实现方案咨询

基于Jetty+JAX-RS/Jersey的Nebula Graph集成测试方案

核心方案概述

采用Testcontainers + 嵌入式Jetty + JUnit 5的组合,完全满足隔离性、Docker化部署、CI/CD友好以及数据验证的需求。所有测试资源(Nebula集群、Jetty服务)均为测试专属,运行后自动销毁,彻底隔离本地/生产环境。


1. 环境隔离与Docker化Nebula部署

使用Testcontainers自动管理Nebula容器,无需手动维护Docker Compose文件,测试代码可直接控制容器生命周期:

依赖配置(Maven为例)

<dependencies>
    <!-- JUnit 5测试框架 -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.9.2</version>
        <scope>test</scope>
    </dependency>
    <!-- Testcontainers容器管理 -->
    <dependency>
        <groupId>org.testcontainers</groupId>
        <artifactId>testcontainers</artifactId>
        <version>1.19.1</version>
        <scope>test</scope>
    </dependency>
    <!-- Nebula Java客户端 -->
    <dependency>
        <groupId>com.vesoft</groupId>
        <artifactId>nebula-java-client</artifactId>
        <version>3.5.0</version>
        <scope>test</scope>
    </dependency>
    <!-- RestAssured接口测试工具 -->
    <dependency>
        <groupId>io.rest-assured</groupId>
        <artifactId>rest-assured</artifactId>
        <version>5.3.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

测试类中启动Nebula容器

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;

@Testcontainers
public abstract class BaseNebulaIntegrationTest {
    // 启动Nebula Graphd服务容器(测试用单实例足够)
    @Container
    protected static final GenericContainer<?> nebulaGraphd = new GenericContainer<>(DockerImageName.parse("vesoft/nebula-graphd:3.5.0"))
            .withExposedPorts(9669)
            .withCommand("--meta_server_addrs=127.0.0.1:9559");

    // 启动Nebula Metad元数据服务容器
    @Container
    protected static final GenericContainer<?> nebulaMetad = new GenericContainer<>(DockerImageName.parse("vesoft/nebula-metad:3.5.0"))
            .withExposedPorts(9559)
            .withCommand("--meta_server_addrs=127.0.0.1:9559 --data_path=/data/meta");

    // 获取Nebula服务连接地址
    protected String getNebulaHost() {
        return nebulaGraphd.getHost();
    }

    protected int getNebulaPort() {
        return nebulaGraphd.getMappedPort(9669);
    }
}

2. 嵌入式Jetty启动JAX-RS应用

在测试中启动嵌入式Jetty,加载JAX-RS资源,随机分配端口避免冲突:

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

public class JettyJaxRsIntegrationTest extends BaseNebulaIntegrationTest {
    private Server jettyServer;
    private int jettyPort;

    @BeforeEach
    void startJetty() throws Exception {
        // 初始化Jetty服务器,使用随机端口避免冲突
        jettyServer = new Server(0);
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        jettyServer.setHandler(context);

        // 注册Jersey Servlet,加载项目JAX-RS资源类
        ServletHolder jerseyServlet = context.addServlet(ServletContainer.class, "/*");
        jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "com.yourproject.resources");
        // 将Nebula连接参数传递给JAX-RS资源
        jerseyServlet.setInitParameter("nebula.host", getNebulaHost());
        jerseyServlet.setInitParameter("nebula.port", String.valueOf(getNebulaPort()));

        jettyServer.start();
        jettyPort = jettyServer.getURI().getPort();
    }

    @AfterEach
    void stopJetty() throws Exception {
        if (jettyServer != null) {
            jettyServer.stop();
            jettyServer.destroy();
        }
    }

    // 获取Jetty服务基础地址
    protected String getJettyBaseUrl() {
        return "http://localhost:" + jettyPort;
    }
}

3. 测试数据生成与断言验证

测试流程:初始化Nebula Schema → 生成测试数据 → 调用JAX-RS接口 → 验证数据/返回结果:

import com.vesoft.nebula.client.graph.NebulaPoolConfig;
import com.vesoft.nebula.client.graph.Session;
import com.vesoft.nebula.client.graph.data.HostAddress;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;

import java.util.Arrays;

import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class UserResourceIntegrationTest extends JettyJaxRsIntegrationTest {

    @Test
    void testCreateUserAndVerifyInNebula() throws Exception {
        // 1. 初始化Nebula Schema(空间、标签)
        try (Session session = getNebulaSession()) {
            session.execute("CREATE SPACE IF NOT EXISTS test_space(vid_type=FIXED_STRING(32))");
            session.execute("USE test_space");
            session.execute("CREATE TAG IF NOT EXISTS user(name string, age int)");
        }

        // 2. 调用JAX-RS接口创建用户
        String userId = "user_001";
        RestAssured.given()
                .baseUri(getJettyBaseUrl())
                .body("{\"id\":\"" + userId + "\", \"name\":\"Alice\", \"age\":25}")
                .contentType("application/json")
                .when()
                .post("/users")
                .then()
                .statusCode(201);

        // 3. 双重验证:接口返回+Nebula数据库查询
        // 验证接口返回结果
        RestAssured.given()
                .baseUri(getJettyBaseUrl())
                .when()
                .get("/users/" + userId)
                .then()
                .body("age", equalTo(25));

        // 验证Nebula数据库中的数据
        try (Session session = getNebulaSession()) {
            session.execute("USE test_space");
            String queryResult = session.execute("MATCH (u:user) WHERE u.name == 'Alice' RETURN u.age").toString();
            // 从查询结果中提取年龄(实际可使用Nebula客户端的结果解析API优化)
            assertEquals("25", extractAgeFromResult(queryResult));
        }
    }

    // 获取Nebula会话连接
    private Session getNebulaSession() throws Exception {
        NebulaPoolConfig poolConfig = new NebulaPoolConfig();
        poolConfig.setMaxConnSize(10);
        com.vesoft.nebula.client.graph.NebulaPool pool = new com.vesoft.nebula.client.graph.NebulaPool();
        pool.init(Arrays.asList(new HostAddress(getNebulaHost(), getNebulaPort())), poolConfig);
        return pool.getSession("root", "nebula", false);
    }

    // 简化的结果解析方法,实际项目可替换为官方API解析
    private String extractAgeFromResult(String result) {
        return result.split("u.age")[1].trim().split("\\s+")[0];
    }
}

4. CI/CD适配

所有测试依赖Docker,只需在CI环境中启用Docker服务即可:

GitHub Actions配置示例(.github/workflows/test.yml)

name: Integration Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
      - name: Enable Docker service
        run: sudo systemctl start docker
      - name: Run integration tests
        run: mvn test -DskipUnitTests=true

内容的提问来源于stack exchange,提问作者saber tabatabaee yazdi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 01:55:18