I would like to use Jacoco to generate a code coverage report on all my tests (androidTest + UnitTest).
So I implemented a step-by-step script (jacoco.gradle) to create a task that allowed me to generate a report that merged two code coverage reports.
My problem is that the html generated file is empty (in app\build\jacocoReport\index.html
):
No class files specified. JaCoCo 0.8.3.201901230119
I execute 'testIntegrationDebugUnitTest' task :
androidTest code coverage report has been created on app/build/reports/coverage/integration/debug/index.html and it's ok.
A 'ec' file has been generated on app\build\outputs\code_coverage\integrationDebugAndroidTest\connected\Pixel_2_API_24(AVD) - 7.0-coverage.ec
A 'exec' file has been generated on app/build/jacoco/testIntegrationDebugUnitTest.exec
Do you have any idea where my problem comes from? Here is my code:
jacoco.gradle :
apply plugin: 'jacoco'
jacoco {
toolVersion = "$jacocoVersion"
reportsDir = file("$buildDir/jacocoReport")
}
project.afterEvaluate {
android.applicationVariants.all { variant ->
def variantName = variant.name
def testTaskName = "test${variantName.capitalize()}UnitTest"
def androidTestCoverageTaskName = "create${variantName.capitalize()}CoverageReport"
tasks.create(name: "${testTaskName}Coverage", type: JacocoReport, dependsOn: ["$testTaskName", "$androidTestCoverageTaskName"]) {
group = "Reporting"
description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build."
reports {
xml.enabled = false
html.enabled = true
html.destination "$buildDir/jacocoReport"
}
def excludes = ['**/R*.class',
'**/*$InjectAdapter.class',
'**/*$ModuleAdapter.class',
'**/*$ViewInjector*.class'
]
def debugTree = fileTree(dir: "$project.buildDir/intermediates/javac/debug", excludes: excludes)
def mainSrc = "$project.projectDir/src/main/java"
sourceDirectories = files([mainSrc])
classDirectories = files([debugTree])
executionData = fileTree(dir: project.buildDir, includes: [
"jacoco/${testTaskName}.exec", "outputs/code_coverage/${variantName}AndroidTest/connected/**/*.ec"
])
}
}
}
gradle project :
buildscript {
ext.kotlin_version = '1.3.21'
ext.jacocoVersion = '0.8.3'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'io.realm:realm-gradle-plugin:5.8.0'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.28.0'
classpath "org.jacoco:org.jacoco.core:$jacocoVersion"
}
}
task installGradle(type: Wrapper) {
group = "*********"
gradleVersion = '4.10.1'
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
app gradle :
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'realm-android'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'io.fabric'
apply from: '../scripts/jacoco.gradle'
android.applicationVariants.all { variant ->
if (variant.name == 'demoDebug' || variant.name == 'evalDebug' || variant.name == 'stagingDebug') {
project.tasks.getByName('process' + variant.name.capitalize() + 'GoogleServices').enabled = false
project.tasks.getByName('fabricGenerateResources' + variant.name.capitalize()).enabled = false
}
}
android {
compileSdkVersion 28
defaultConfig {
applicationId "***********"
minSdkVersion 23
targetSdkVersion 28
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
debug {
testCoverageEnabled true
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'com.google.firebase:firebase-core:16.0.8'
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.25.1'
testImplementation 'android.arch.core:core-testing:1.1.1'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'org.mockito:mockito-android:2.25.1'
androidTestImplementation 'android.arch.core:core-testing:1.1.1'
}
The JaCoCo Report Aggregation plugin (plugin id: jacoco-report-aggregation) provides the ability to aggregate the results of multiple JaCoCo code coverage reports (potentially spanning multiple Gradle projects) into a single HTML report.
By default, a HTML report is generated at $buildDir /reports/jacoco/test. While tests should be executed before generation of the report, the jacocoTestReport task does not depend on the test task.
The JacocoReport task can be used to generate code coverage reports in different formats. It implements the standard Gradle type Reporting and exposes a report container of type JacocoReportsContainer. Example 4. Configuring test task This feature requires the use of JaCoCo version 0.6.3 or higher.
We’ll occasionally send you account related emails. Already on GitHub? Sign in to your account Given a jacocoTestReport task, it does not generate xml report EVEN THOUGH it generates html reports correctly.
This is a common problem, you need to change the debugTree
property to:
//java compiled classes
def javaTree = fileTree(dir: "$project.buildDir/intermediates/javac/debug/classes", excludes: fileFilter)
//kotlin compiled classes
def kotlinTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
//...etc...
classDirectories.from = files([javaTree, kotlinTree])
debug
can be any variant, you can use $variantName
in place of it if you know what you are doing
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With