Coverage Counters
JaCoCo uses a set of different counters to calculate coverage metrics. The foundation of all counters are so called basic blocks. All other counters are derived from the basic block coverage information. While JaCoCo counters appear to be closely related to Java source code they are actually only derived from Java class files. In cases where the Java compiler creates so called synthetic code to reflect certain Java language constructs counters may therefore show unexpected results.
Basic Blocks
A basic block – mostly just referred to as block in the APIs and reports – represents a consecutive sequence of byte code instructions and is a unit that will either execute completely or not all. The single exception from this definition occurs when the java exception mechanism comes to action (i.e. a java exception "flies"). This always interrupts the current blocks execution. The boundaries between blocks are
- return instructions,
- throw instructions,
- (conditional) jump instructions and
- target labels referred from jump, try/catch or switch instructions.
The JaCoCo instrumentation mechanism inserts a probe at the end of every block. When the probe gets executed the block is considered executed. This results in the major drawback of basic block based probes:
Blocks that encounter an exception somewhere in the middle of their execution will be considered as not executed. This is correct as the block actually didn't get executed but JaCoCo won't be able to tell which lines of the block executed and which didn't.
Beside this, basic block code coverage has been proven to work very efficiently even with huge applications under test. The reasons are that the blocks can be easily determined at instrumentation time. The amount of inserted probes offer a good tradeoff between runtime overhead and report granularity. And last but not least basic blocks can be determined even if the class files have not been compiled in debug mode and therefore do not contain any source line information. Therefore all coverage counters except the line counter will work also in this case and provide useful coverage information e.g. for binary third party libraries.
Instructions
For each block the number of included byte code instructions can be easily determined. The instruction counter summarizes the number of single byte code instructions that belong to executed blocks. As blocks may be of different length, instructions give a good measure of block size and can serve as a replacement when no line information is available.
Lines
For all class files that have been compiled in debug mode with source line information, coverage information for individual lines can be derived from basic blocks. Each block may span one or multiple lines of source code. On the other hand a single line of source may belong to multiple blocks. A source line is considered executed when at least one block that includes this line has been executed.
Due to the fact that a single line may belong to more than one block partial coverage can happen if some of the blocks are executed while others are not. This is typically the case with boolean expressions. While partially covered lines are seen as executed due to the definition in the previous paragraph, they are highlighted in yellow color in the coverage reports.
Methods
Each non-abstract method consists of at least one block. A method is considered as executed when at least one block has been executed. As JaCoCo works on byte code level also constructors and static initializers are counted as methods. Some of these methods may not have a direct correspondence in Java source code, like implicit and thus generated default constructors or initializers for constants.
Classes
A class is considered as executed when at least one of its methods has been executed. Note that JaCoCo considers constructors as well as static initializers as methods. As Java interface types may contain static initializers such interfaces are also considered as executable classes.