A couple of Gradle plugins to make Android modules work with JaCoCo Report Aggregation Plugin and Test Report Aggregation Plugin
Note
Since the arrival of Kover 0.8.0-Beta2
, this project loses momentum,
as test aggregation of JVM/Kotlin/Android mono-repos is supported out of the box, providing a much better coverage experience than JaCoCo
plugins {
id("org.jetbrains.kotlinx.kover") version "0.8.0-Beta2"
}
subprojects { apply(plugin = "org.jetbrains.kotlinx.kover") }
kover.merge { allProjects() }
Apply the plugin at the root project:
plugins {
id("io.github.gmazzo.test.aggregation.coverage") version "<latest>"
// and/or
id("io.github.gmazzo.test.aggregation.results") version "<latest>"
}
Note
This plugin can not be applied along with the java
one because it conflicts.
If you have a Java root project, it's recommended to move it to a dedicated module
The jacocoAggregatedReport
(for coverage
) and testAggregatedReport
(for results
) will be created
to aggregate test results from all projects in the build
The following is the old README.me of the demo project of my Medium article about this topic, now promoted to dedicated Gradle plugins: io.github.gmazzo.test.aggregation.coverage and io.github.gmazzo.test.aggregation.results
The plugins will automatically aggregate android
modules and java
modules that also apply jacoco
plugin on the
jacocoAggregation
and the testReportAggregation
configurations.
You control which projects are effectively included by using the DSL:
testAggregation {
modules {
include(project(":app"))
exclude(projects.lib) // typesafe accessors are also supported!
}
}
You can use the DSL to include/exclude .class
files from the aggregated JaCoCo coverage report:
testAggregation {
coverage {
include("com/**/Login*") // will only include classes starting with `com.` containing `Login` on its name
}
}
It's important to realize the filtering is done at .class
file level (compiled classes).
You should not use classes names here but GLOB patterns.
This is an example project that illustrates how can the
JaCoCo Report Aggregation Plugin and
Test Report Aggregation Plugin
can be used to aggregate a complex Android project with JVM modules in a single :jacocoAggregatedReport
and :testAggregatedReport
tasks.
- A
plugin
included build that provides thecoverage
root plugin - A
demo-project
with:- An
app
android module (with Robolectric tests) - A
login
android library module (with JUnit4/JVM tests) - A
domain
jvm module (with tests)
- An
The plugin fills the gaps between AGP and JaCoCo Report Aggregation Plugin by providing the necessary setup missing:
- It applies
jacoco-report-aggregation
andtest-report-aggregation
at root project - Creates
jacocoAggregatedReport
andtestAggregatedReport
forTestSuiteType.UNIT_TEST
- If a module applies
jacoco
plugin, it adds it to thejacocoAggregation
andtestReportAggregation
root configurations - If a module applies the
java
plugin, makes its childjacocoAggregatedReport
task to depend ontest
- If a module applies the
android
plugin:- it enables by default
BuildType.enableUnitTestCoverage
ondebug
to produce jacoco exec files - adds the
codeCoverageExecutionData
,codeCoverageSources
,codeCoverageElements
(classes) andtestResultsElements
outgoing variants, to allowjacoco-report-aggregation
andtest-report-aggregation
to aggregate it
- it enables by default
Please note that JVM still need to manually apply jacoco
plugin (this is an intentional opt-in behavior)
build.gradle.kts
The task :jacocoAggregatedReport
is added to the root project when applying this plugin and it can be
run to produce the report. All dependent test
tasks will be run too to produce the required execution data.
The same for :testAggregatedReport
:
The same as JaCoCo Plugin
supports Enforcing code coverage metrics
this plugin adds a ':jacocoAggregatedCoverageVerification' to provide the same feature, but with the aggregated metrics:
tasks.jacocoAggregatedCoverageVerification {
violationRules {
rule {
limit {
minimum = "0.5".toBigDecimal()
}
}
rule {
isEnabled = false
element = "CLASS"
includes = listOf("org.gradle.*")
limit {
counter = "LINE"
value = "TOTALCOUNT"
maximum = "0.3".toBigDecimal()
}
}
}
}
This is an opt-in/out switch meant to be used when having productFlavors
.
enableUnitTestCoverage
is a BuildType
setting (default on debug
). When having flavors, you'll
have many coverage reports to produce targeting debug
(one per flavor variant).
You can use enableUnitTestCoverage.set(false)
to turn aggregation off for an specific ProductFlavor
.
Basically, the variant won't be added to the codeCoverageExecutionData
configuration, so :jacocoAggregatedReport
won't compute it
For instance, app
module has a environment
dimension with 2 flavors: stage
and prod
.
Without any extra settings, :jacocoAggregatedReport
will depend on :app:testStageDebugUnitTest
and
:app:testProdDebugUnitTest
(running its src/test/
tests effectively twice).
You may choose which flavors participates in the aggregated report by doing:
productFlavors {
create("stage") {
dimension = "environment"
}
create("prod") {
dimension = "environment"
aggregateTestCoverage.set(false)
}
}
where it effectively only run :app:testStageDebugUnitTest
Note
The aggregateTestCoverage
DSL applies for both :jacocoAggregatedReport
and :testAggregatedReport
tasks