Longi Longi - 7 months ago 74
Android Question

JaCoCo doesn't work with Robolectric tests

I wanted to generate code coverage reports on my JUnit tests in my android project so I added the JaCoCo gradle plugin. This is my project level

build.gradle
file:

apply plugin: 'jacoco'

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-beta6'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}

allprojects {
repositories {
jcenter()
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

subprojects { prj ->
apply plugin: 'jacoco'

jacoco {
toolVersion '0.7.6.201602180812'
}

task jacocoReport(type: JacocoReport, dependsOn: 'testDebugUnitTest') {
group = 'Reporting'
description = 'Generate Jacoco coverage reports after running tests.'

reports {
xml {
enabled = true
destination "${prj.buildDir}/reports/jacoco/jacoco.xml"
}
html {
enabled = true
destination "${prj.buildDir}/reports/jacoco"
}
}

classDirectories = fileTree(
dir: 'build/intermediates/classes/debug',
excludes: [
'**/R*.class',
'**/BuildConfig*',
'**/*$$*'
]
)

sourceDirectories = files('src/main/java')
executionData = files('build/jacoco/testDebugUnitTest.exec')

doFirst {
files('build/intermediates/classes/debug').getFiles().each { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
}

jacoco {
toolVersion '0.7.6.201602180812'
}

task jacocoFullReport(type: JacocoReport, group: 'Coverage reports') {
group = 'Reporting'
description = 'Generates an aggregate report from all subprojects'

//noinspection GrUnresolvedAccess
dependsOn(subprojects.jacocoReport)

additionalSourceDirs = project.files(subprojects.jacocoReport.sourceDirectories)
sourceDirectories = project.files(subprojects.jacocoReport.sourceDirectories)
classDirectories = project.files(subprojects.jacocoReport.classDirectories)
executionData = project.files(subprojects.jacocoReport.executionData)

reports {
xml {
enabled = true
destination "${buildDir}/reports/jacoco/full/jacoco.xml"
}
html {
enabled = true
destination "${buildDir}/reports/jacoco/full"
}
}

doFirst {
//noinspection GroovyAssignabilityCheck
executionData = files(executionData.findAll { it.exists() })
}
}


It works great by running
./gradlew jacocoFullReport
. But unfortunately coverage is not reported for the tests that are run with the
RobolectricTestRunner
(instructions that are obviously called in the tests are not reported as covered). Tests with no
@RunWith
annotation or run with
MockitoJUnitTestRunner
report coverage just fine.

Any help would be appreciated to fix this problem.

Update 1: I noticed that I should be using the
RobolectricGradleTestRunner
. But it didn't help.

Answer Source

It is known issue with the possible workaround - https://github.com/jacoco/jacoco/pull/288

Or downgrade jacoco version to 0.7.1.201405082137

UPDATE

The workaround is not needed anymore. You must use gradle version 2.13 and jacoco version 0.7.6.201602180812.

Update root build.gradle:

buildscript {
    dependencies {
        classpath 'org.jacoco:org.jacoco.core:0.7.6.201602180812'
    }
}

task wrapper( type: Wrapper ) {
  gradleVersion = '2.13'
}

Run ./gradlew wrapper

Update project build.gradle:

apply plugin: 'jacoco'

android {
  testOptions {
    unitTests.all {
      jacoco {
        includeNoLocationClasses = true
      }
    }
  }
}