I'm trying to use jacoco in a multi module android project. The project is similar to NowInAndroid. The Jacoco.kt file is the same:
private val coverageExclusions = listOf(
// Android
"**/R.class",
"**/R\$*.class",
"**/BuildConfig.*",
"**/Manifest*.*",
"**/*_Hilt*.class",
"**/Hilt_*.class",
)
private fun String.capitalize() = replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
}
internal fun Project.configureJacoco(
androidComponentsExtension: AndroidComponentsExtension<*, *, *>
) {
configure<JacocoPluginExtension> {
toolVersion = "0.8.7"
}
androidComponentsExtension.onVariants { variant ->
val myObjFactory = project.objects
val buildDir = layout.buildDirectory.get().asFile
val allJars: ListProperty<RegularFile> = myObjFactory.listProperty(RegularFile::class.java)
val allDirectories: ListProperty<Directory> = myObjFactory.listProperty(Directory::class.java)
val reportTask =
tasks.register("create${variant.name.capitalize()}CombinedCoverageReport", JacocoReport::class) {
classDirectories.setFrom(
allJars,
allDirectories.map { dirs ->
dirs.map { dir ->
myObjFactory.fileTree().setDir(dir).exclude(coverageExclusions)
}
}
)
reports {
xml.required.set(true)
html.required.set(true)
}
// TODO: This is missing files in src/debug/, src/prod, src/demo, src/demoDebug...
sourceDirectories.setFrom(files("$projectDir/src/main"))
println("This is the projectDir -> ${projectDir}")
executionData.setFrom(
project.fileTree("$buildDir/outputs/unit_test_code_coverage/${variant.name}UnitTest")
.matching { include("**/*.exec") },
project.fileTree("$buildDir/outputs/code_coverage/${variant.name}AndroidTest")
.matching { include("**/*.ec") }
)
}
variant.artifacts.forScope(ScopedArtifacts.Scope.PROJECT)
.use(reportTask)
.toGet(
ScopedArtifact.CLASSES,
{ _ -> allJars },
{ _ -> allDirectories },
)
}
tasks.withType<Test>().configureEach {
configure<JacocoTaskExtension> {
// Required for JaCoCo + Robolectric
// https://github.com/robolectric/robolectric/issues/2230
isIncludeNoLocationClasses = true
// Required for JDK 11 with the above
// https://github.com/gradle/gradle/issues/5184#issuecomment-391982009
excludes = listOf("jdk.internal.*")
}
}
}
I've also created an AndroidApplicationJacocoConventionPlugin
and an AndroidLibraryJacocoConventionPlugin
. Just like NowInAndroid.
When I run the androidTest in the app module it works fine, the coverage.ec file is created, but when I try to run it in a library module it creates the coverage.ec but the file is empty, can someone help me with it?
I just don't understand why it works for the application module, but not for the other modules.
I found out that the problem was that the apk generated by the androidTest wasn't debuggable in my project. Adding:
(this as com.android.build.gradle.internal.dsl.BuildType).isDebuggable = true
For the library module solved the problem.