Merge Jacoco coverage reports for multiproject setups

I’ve read various solutions to this problem. But some are outdated and some seems very elaborative. So I wrote my own little solution by putting this in the root project’s build.gradle.kts

tasks.register<JacocoReport>("aggregatedJacocoReport") {
    subprojects {
        plugins.withType<JacocoPlugin>().configureEach {
            if (projectDir.resolve("src/main").exists())
                sourceSets(project.the<SourceSetContainer>()["main"])

            tasks.findByName("test")?.let {
                if (projectDir.resolve("src/test").exists()) {
                    val testTask = it
                    executionData(testTask)
                }
            }
        }
    }

    reports {
        xml.required.set(true)
        html.required.set(true)
    }
}

That seemed to do the trick for me. It checks that there actually are any sources in the subproject (since you in a multi project sometimes have some folders that are just folders and not a module with code). It also checks that there are any tests that can generate test data.

This is a really hacky solution imho.
And it also has race conditions, for example if you want to use parallel configuration and so on.
I’d still recommend using the proper way to publish things between projects like described in the Gradle docs and for exactly this use-case.

I have used the referenced example from the Gradle documentation in order to generate an aggregated JaCoCo report in a multiproject build.
It works fine, but I have a problem, excluding some classes from the report, e.g. generated ones.
Are there any examples on how to do this?

(I do have one solution now, which is not optimal for me: I put all generated code into dedicated subprojects and exclude them from coverage analysis. But I would like to know how to exclude only certain classes.)

@Vampire do you have examples on how to do this?

JaCoCo should ignore all classes that are annotated with any annotation with simple name Generated and iirc retention class, but I might remember wrongly.
So easiest is you care for the generated classes to have a proper Generated annotation.

Other than that, I’d say you exclude like you also exclude with single-project report?
I actually never did a multi-project JaCoCo report myself yet.

Ok thank you for the hint on annotations.
In some situations this may help. But using external generators make it sometimes hard to get generated code with custom annotations.

But I will have a look at it.

In that cases I report to that external generator that it should add this annotation and simply add a post-processing step to the code generation that just adds the annotation via a simple replace operation.

And actually fitting to the topic, Gradle 7.4 adds built-in ways to easily produce a combined test report and a combined JaCoCo report in a multi-project build.

2 Likes

Hello there!

I know I am reliving this topic, but this is still very obscure to me. As I read in other posts, I searched a lot at the internet and still couldn’t find a solution for a jacoco coverage in multiprojects. I am sure that @Vampire mentioned the JaCoCo Report Aggregation. I tried to follow, but it didn’t work for me ( or I did some wrong configuration).

I am not developing for Android, but I am devloping a Kotlin Backend application.

So, trying to be very clear: Is there any definitive guide or examples that I could follow to achieve this?

What did not work?
The JaCoCo Report Aggregation plugin is working fine for non-Android projects in the way it is designed, that is merging reports across projects for the same test suite type.

Thank you for your response, @Vampire. I’ll set up a sample project to provide you with a more thorough answer, as it’s been some time since I last tested the Jacoco aggregation plugin.

1 Like