基于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
相关产品推荐
相关产品推荐

