What is the difference between jacoco branch coverage and Sonar condition coverage?

Alban picture Alban · Apr 17, 2018 · Viewed 9.8k times · Source

I'm trying to analyze java code with the SonarQube Scanner (version 3.1.0.1141).

  • SonarQube version : 5.6.6
  • Sonar Java plugin version : 4.12.0.11033
  • jacoco version : 0.8.0

I have filled the sonar-project.properties with those properties :

# Sonar sources and metadata
sonar.language=java
sonar.sources=src/main
sonar.java.source=1.8
sonar.sourceEncoding=UTF-8
sonar.java.binaries=target/classes
sonar.java.libraries=target/lib

sonar.tests=src/test
sonar.java.coveragePlugin=jacoco
sonar.junit.reportsPath=target/surefire-reports
sonar.surefire.reportsPath=target/surefire-reports

While jacoco report gives me this result for one class :

  • Coverage : 84%
  • Branch Coverage : 71%
  • Missed : 9
  • Complexity : 24
  • Missed : 6
  • Lines : 69
  • Missed : 0
  • Methods : 8
  • Missed : 0
  • Classes : 1

SonarQube displays the measures :

  • Condition coverage 62,5%
  • Coverage 81,7%
  • Line coverage 92,8%
  • Lines to cover 69
  • Overall condition coverage 62,5%
  • Overall coverage 81,7%
  • Overall line coverage 92,8%
  • Overall uncovered branches 15
  • Overall uncovered lines 5
  • Uncovered branches 15
  • Uncovered lines 5

According to the sonar metric definition page, the sonar key for condition coverage is branch_coverage, so I thought condition and branch coverage are the same things.

How to explain the different results?

Answer

Gerald Mücke picture Gerald Mücke · Apr 18, 2018

Given you have some construct as

if(a == 1 && b == 2) {
  //do this
} else {
  //do that
}

You have two branches

  • do this
  • do that

And two conditions

  • a == 1 (cond1)
  • b == 2 (cond2)

If you have two test cases

  • test(a == 1, b == 2)
  • test(a == 2, b == 2)

You're covering both branches because the combined condition of (cond1 && cond2) is either false or true,

But you only cover cond1 fully and only half of cond2, thats 75% condition coverage.

To get full condition coverage, you need an additional test

  • test(a == 1, b == 1)

Edit

Both tools calculate the coverage using the branch information per line. I run a test on some of my code, and the number of "conditions to cover" (Sonarqube) matches the number of total "Branches" in Jacoco report - but I used the most recent versions for jacoco and Sonarqube/sonar-java. So apart from the name, but measures are/should be the same.

But given the numbers you provide, there seems something odd with your analysis in general. It's not only the percentage-values that differ, but the absolute ones as well (9 uncovered branches in Jacoco vs 15 uncovered Branches in Sonarqube).

So I checked the versions you're using - jacoco 0.8.0 and the sonar-java plugin v4.11.0.11033 which uses jacoco 0.7.9.

The release notes for Jacoco 0.8.0 read

During creation of reports various compiler generated artifacts are filtered out, which otherwise require unnecessary and sometimes impossible tricks to not have partial or missed coverage:

  • Methods valueOf and values of enum types (GitHub #491).
  • Private empty no-argument constructors (GitHub #529).
  • Methods annotated with @lombok.Generated to better integrate with Lombok >= 1.16.14. Initial analysis and contribution by Rüdiger zu Dohna (@t1) (GitHub #513).
  • Methods annotated with @groovy.transform.Generated to better integrate with Groovy >= 2.5.0. Thanks to Andres Almiray (@aalmiray) for adding the annotation to Groovy (GitHub #610).
  • Part of bytecode for synchronized blocks (GitHub #501).
  • Part of bytecode for try-with-resources statements (GitHub #500).
  • Part of bytecode for finally blocks (GitHub #604).
  • Part of bytecode for switch statements on java.lang.String values (GitHub > #596).

So my best guess here would be, that the report generated by Jacoco 0.8.0 filtered out some of the mentioned generated artifacts effectively reducing to total number of branches. Sonar-Java however uses Jacoco 0.7.9 which does not filter out generated artifacts and therefore the numbers are higher (and the coverage lower).

Maybe you should either downgrade your jacoco version to 0.7.9 or upgrade the sonar-java plugin.