Reputation: 3973
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.
Upvotes: 27
Views: 8811
Reputation: 1
Same issue here, but the solutions provided no longer work with Gradle 8.7/AGP 8.4.1. For me, it was working with this piece of code in the module's build.gradle.kts file:
tasks.withType(Test::class) {
configure<JacocoTaskExtension> {
isIncludeNoLocationClasses = true
excludes = listOf("jdk.internal.*")
}
}
I have enabled the jacoco plugin in the corresponding section:
plugins {
...
id("jacoco")
}
Then I setup code coverage instrumentation in the android section:
android {
buildTypes {
debug {
enableUnitTestCoverage = true
}
}
}
And finally I have added the Robolectric dependency:
dependencies {
...
testImplementation("org.robolectric:robolectric:4.12.2")
}
For the full implementation, see here: https://github.com/Futsch1/medTimer/blob/main/app/build.gradle.kts
Upvotes: 0
Reputation: 349
This is an old issue, but for those who are still facing, it is worth mentioning that if you are setting up JaCoCo + Robolectric + Espresso - you will indeed be using includeNoLocationClasses
, but still will see this error with Java9+ and probably end up here. Add the below snippet to your module build.gradle file
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
}
Upvotes: 4
Reputation: 2869
change coverage runner to jacoco in android studio 1- select app(root of the project) 2 click on menu (run --> Edit configurations --> code coverage --> choose JaCoCo).
Upvotes: -1
Reputation: 2154
The accepted answer is a bit dated. Here is a similar fix we just implemented. In the module (i.e. app) build.gradle add:
apply plugin: 'jacoco'
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
This does require JaCoCo 7.6+, but you are likely using it already.
Notes for Studio:
Upvotes: 8
Reputation: 854
I had the same issue. I changed the jacoco plugin version and added includenolocationclasses property. Here is the working jacoco.gradle file (I am using gradle wrapper 2.14.1):
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.7.6.201602180812"
}
android {
testOptions {
unitTests.all {
jacoco {
includeNoLocationClasses = true
}
}
}
}
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
println(buildTypes)
println(productFlavors)
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
println("SourceName:${sourceName}")
println("SourcePath:${sourcePath}")
println("testTaskName:${testTaskName}")
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
excludes: ['**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*']
)
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
println("${project.buildDir}/jacoco/${testTaskName}.exec")
reports {
xml.enabled = true
html.enabled = true
}
}
}
}
}
Upvotes: 3
Reputation: 20140
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
}
}
}
}
Upvotes: 25
Reputation: 174
I was facing the same issue but now it is resolved for me by following this link,
issue link: https://github.com/robolectric/robolectric/issues/2230
Solution for this problem is mentioned here:
Upvotes: 4