Incremental Code Coverage Plugin for Android Using JaCoCo: Design and Implementation
This article describes the design and implementation of a Gradle plugin that extends JaCoCo to collect incremental code‑coverage data for Android applications, covering project background, significance, JaCoCo injection mechanisms, compile‑time instrumentation, runtime data handling, report generation, and practical results.
In the software delivery process, testing teams often rely on manually written test cases, which can miss edge cases, code branches, or recent code changes, leading to quality gaps. To improve stability for a mobile app, the team needed a tool that could precisely collect code‑coverage data for incremental changes.
Project significance includes identifying uncovered code, detecting dead code, and using coverage metrics as a risk indicator for both developer self‑testing and QA validation.
Exploration revealed that popular tools like JaCoCo and EMMA only provide full‑project coverage, which is too coarse for incremental analysis. The decision was made to customize JaCoCo.
JaCoCo injection principle relies on byte‑code instrumentation. Two injection modes exist:
Offline – instrument class files before they are packaged.
On‑The‑Fly – use a Java agent to instrument classes at load time (not suitable for Android, so Offline is chosen).
The plugin inserts probes only into methods that differ between two Git branches. The workflow is:
Obtain the list of changed files with git diff origin/feature … origin/master --name-only .
Copy the corresponding .class files of both branches into temporary directories.
Filter out non‑relevant classes and generate a diff method set.
Modify JaCoCo to instrument only those diff methods.
Compile‑time implementation uses a Gradle Transform. A configuration object ( class JacocoExtension { … } ) defines options such as branch name, exec directory, source and class directories, and inclusion filters. The process includes:
Git management of compiled class files.
Extraction of diff method signatures via ASM ( class DiffClassVisitor extends ClassVisitor { … } ).
Insertion of probes using JaCoCo’s Instrumenter and ProbeInserter when a method matches the diff set.
Runtime handling initializes the coverage manager in the application class, uploads previously recorded .ec files, and generates a new coverage file on activity destruction.
Report generation is integrated into a Jenkins job. The BranchDiffTask downloads .ec files, re‑computes the diff method set, and invokes JaCoCo’s ReportGenerator to produce HTML reports. The reports highlight uncovered lines (red), fully covered lines (green), and branch coverage status.
Project summary – the plugin provides incremental, method‑level coverage for Android, helping the team achieve higher test completeness, identify blind spots, and continuously improve code quality. The first version is already in use in the production app, with plans to refine diff detection and usability.
Beike Product & Technology
As Beike's official product and technology account, we are committed to building a platform for sharing Beike's product and technology insights, targeting internet/O2O developers and product professionals. We share high-quality original articles, tech salon events, and recruitment information weekly. Welcome to follow us.
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.