Operations 10 min read

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.

NetEase Media Technology Team
NetEase Media Technology Team
NetEase Media Technology Team
Building a Precise Testing Framework with Java‑Callgraph, Neo4j, and Jenkins

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.

Architecture diagram
Architecture diagram

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 interface

Neo4j’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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ci/cdtestingNeo4jgraph-analysisJenkinsjava-callgraph
NetEase Media Technology Team
Written by

NetEase Media Technology Team

NetEase Media Technology Team

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.