Building a Precise Testing Framework with Java‑Callgraph, Neo4j, and Jenkins
This article explains how to construct a precise testing system for Java services by combining java‑callgraph for call‑graph extraction, Neo4j for graph storage, and Jenkins with Overmind for automated diff analysis and report generation, detailing architecture, tool setup, scripts, and integration steps.
Background and Motivation
When a low‑level service changes, QA teams need a quantitative way to know whether the impact is minor or extensive. The goal is to provide a transparent, end‑to‑end testing workflow that automatically discovers method‑level call relationships, maps them to API endpoints, and guides test planning.
Overall Architecture
The solution integrates several open‑source and internal tools: java‑callgraph for extracting method call graphs, a full‑link tracing platform for runtime data, Neo4j for graph storage, Jenkins for CI orchestration, and Overmind as the test‑flow engine. The architecture diagram is shown below.
Component 1: java‑callgraph
The open‑source java‑callgraph tool (https://github.com/gousiosg/java-callgraph) generates static or dynamic call graphs for Java projects. After building the project with Maven ( mvn install), three JARs are produced:
javacg‑0.1‑SNAPSHOT.jar – core jar for both static and dynamic graphs
javacg‑0.1‑SNAPSHOT‑static.jar – static call‑graph generator
javacg‑0.1‑SNAPSHOT‑dycg‑agent.jar – dynamic call‑graph agent
Static analysis is invoked as:
java -jar javacg-0.1-SNAPSHOT-static.jar lib1.jar lib2.jar ...The output encodes call relationships in the form
M:Class1:<method1>(args) (type) Class2:<method2>(args), indicating that method1 calls method2.
Component 2: Javassist for Method‑Parameter Extraction
To map each call to its corresponding Spring MVC endpoint, the project uses Javassist to read method signatures and parameter names. A representative snippet is:
private String getMethodParams(String className, String methodName) {
StringBuilder result = new StringBuilder();
try {
ClassPool pool = ClassPool.getDefault();
ClassClassPath classPath = new ClassClassPath(this.getClass());
pool.insertClassPath(classPath);
CtMethod cm = pool.getMethod(className, methodName);
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
result.append(cm.getName()).append("(");
CtClass[] pTypes = cm.getParameterTypes();
String[] paramNames = new String[pTypes.length];
// ... extract names ...
} catch (Exception e) {
e.printStackTrace();
}
return result.toString();
}This enables the system to associate each Java method with its @RequestMapping URL and parameter list.
Component 3: Neo4j Graph Database
Because relational databases struggle with highly connected call‑graph data, the solution stores nodes and relationships in Neo4j. Nodes represent interfaces or methods, and edges capture call dependencies. Example node JSON:
{
"name": "/api/v1/elephant/cindex/batch/xxInterface.do",
"project": "elephant"
}Cypher queries retrieve affected interfaces. A typical query to find all interfaces reachable from a changed method A is:
MATCH ownership = shortestPath((a:InterfaceNode)-[*0..]->(b:MethodNode{name:"A"}))
WHERE NOT ()-[:has]->(a)
RETURN head(nodes(ownership)).name AS interfaceNeo4j’s pattern‑matching syntax ( () for nodes, [] for relationships) makes these traversals efficient.
Component 4: Jenkins Job Configuration
Jenkins jobs are created to automate the workflow:
Create a new job.
Configure the JAR path, target API list, and branch name.
Set up a trigger (e.g., on push to master).
Attach scripts that parse diffs, update Neo4j, and send email reports.
Job configuration screenshots are omitted for brevity.
Component 5: Supporting Scripts
Several custom scripts glue the pipeline together: write2neo4j-new.sh – parses call‑graph output and writes nodes/relationships to Neo4j. getInterface – queries Neo4j to retrieve interfaces impacted by a specific method. checkLog.py – normalizes log formats. sendEmail.py – emails a tailored precise‑testing report to QA engineers.
Integration with Overmind
Overmind triggers the Jenkins job when a new test version is submitted. It passes the diff between the test version and master to the pipeline, which then updates Neo4j and generates a detailed impact report.
Future Plans
The team plans to extend the graph to cover inter‑project service call topologies, prioritize impacted interfaces, and continuously refine the workflow based on QA feedback.
Conclusion
The precise testing framework provides a quantifiable, automated way to assess code changes, guide QA effort, and reduce blind regression testing across the media backend ecosystem.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
