如何为JanusGraph编写JUnit测试并Mock带属性的Vertex?
解决方案:Mock Vertex 对象 或 使用内存数据库
一、Mock 方式(轻量,适合简单逻辑)
JanusGraph 的 Traversal 是链式调用,仅 Mock 单个对象会导致空指针,需要完整 Mock 每一步调用链,同时模拟 Vertex 的属性返回:
1. 初始化 Mock 对象
确保用 Mockito 初始化所有需要的对象(通过 @RunWith(MockitoJUnitRunner.class) 或 MockitoAnnotations.openMocks(this) 开启 Mock 支持):
@Mock private GraphTraversalSource graphSource; @Mock private Vertex mockJobRoleVertex; @Mock private VertexProperty<String> mockJobCodeProp; @Mock private VertexProperty<String> mockVLabelProp;
2. 模拟 Vertex 的属性返回
让 Mock 的 Vertex 在调用 property() 时返回对应属性值:
// 模拟jobCode属性 when(mockJobRoleVertex.property("jobCode")).thenReturn(mockJobCodeProp); when(mockJobCodeProp.value()).thenReturn(JOBCODE); // 模拟vLabel属性 when(mockJobRoleVertex.property("vLabel")).thenReturn(mockVLabelProp); when(mockVLabelProp.value()).thenReturn("JobRole");
3. Mock Traversal 链式调用
场景1:查询到已存在的 Vertex
// 模拟 graphSource.V() -> has("vLabel") -> has("jobCode") 的调用链 GraphTraversal<Vertex, Vertex> vTraversal = mock(GraphTraversal.class); when(graphSource.V()).thenReturn(vTraversal); GraphTraversal<Vertex, Vertex> vLabelTraversal = mock(GraphTraversal.class); when(vTraversal.has("vLabel", "JobRole")).thenReturn(vLabelTraversal); GraphTraversal<Vertex, Vertex> jobCodeTraversal = mock(GraphTraversal.class); when(vLabelTraversal.has("jobCode", JOBCODE)).thenReturn(jobCodeTraversal); // 模拟查询有结果,返回Mock的Vertex when(jobCodeTraversal.hasNext()).thenReturn(true); when(jobCodeTraversal.next()).thenReturn(mockJobRoleVertex);
场景2:未查询到 Vertex,执行 addV 逻辑
// 先模拟查询无结果 when(jobCodeTraversal.hasNext()).thenReturn(false); // 模拟 addV("JobRole") -> property(jobCode) 的调用链 GraphTraversal<Vertex, Vertex> addVTraversal = mock(GraphTraversal.class); when(graphSource.addV("JobRole")).thenReturn(addVTraversal); GraphTraversal<Vertex, Vertex> jobCodePropTraversal = mock(GraphTraversal.class); when(addVTraversal.property(VertexProperty.Cardinality.single, "jobCode", JOBCODE)).thenReturn(jobCodePropTraversal); // 模拟添加后返回Mock的Vertex when(jobCodePropTraversal.next()).thenReturn(mockJobRoleVertex);
4. Mock 后续的 property 更新逻辑
避免最后一步 graphSource.V(JobRole).property(...).next() 触发空指针:
GraphTraversal<Vertex, Vertex> vertexTraversal = mock(GraphTraversal.class); when(graphSource.V(mockJobRoleVertex)).thenReturn(vertexTraversal); GraphTraversal<Vertex, Vertex> vLabelPropTraversal = mock(GraphTraversal.class); when(vertexTraversal.property(VertexProperty.Cardinality.single, "vLabel", "JobRole")).thenReturn(vLabelPropTraversal); when(vLabelPropTraversal.next()).thenReturn(mockJobRoleVertex);
二、内存数据库方式(贴近真实场景,适合复杂逻辑)
如果 Mock 链式调用太繁琐,直接用 JanusGraph 的内存后端,无需 Mock 任何对象,测试更贴近生产环境行为:
1. 添加测试依赖
<dependency> <groupId>org.janusgraph</groupId> <artifactId>janusgraph-inmemory</artifactId> <version>你的JanusGraph版本</version> <scope>test</scope> </dependency>
2. 初始化内存数据库
private JanusGraph graph; private GraphTraversalSource graphSource; @Before public void setUp() { // 初始化内存JanusGraph实例 graph = JanusGraphFactory.build() .set("storage.backend", "inmemory") .open(); graphSource = graph.traversal(); } @After public void tearDown() { // 测试结束关闭数据库,释放资源 if (graph != null) { graph.close(); } }
3. 编写测试用例
直接像生产环境一样操作数据,验证业务逻辑结果:
// 测试查询存在的场景:先插入测试数据 graphSource.addV("JobRole") .property(VertexProperty.Cardinality.single, "jobCode", JOBCODE) .property(VertexProperty.Cardinality.single, "vLabel", "JobRole") .next(); // 调用你的业务逻辑方法 Vertex jobRole = yourService.getOrCreateJobRole(JOBCODE); // 验证属性值正确性 assertEquals(JOBCODE, jobRole.property("jobCode").value()); assertEquals("JobRole", jobRole.property("vLabel").value());
总结
- 简单业务逻辑优先选 Mock 方式,轻量但需维护完整调用链;
- 复杂逻辑或需验证真实数据库行为时,选内存数据库方式,无需处理 Mock 细节,测试可信度更高。
内容的提问来源于stack exchange,提问作者user19442466
相关产品推荐
相关产品推荐

