# Reporting code coverage with JaCoCo Sample

version 6.4

- Groovy DSL

- Kotlin DSL

| You can open this sample inside an IDE using the IntelliJ native importer or Eclipse Buildship.

This sample shows how to test Java projects with JaCoCo in Gradle.

To collect code coverage across multiple subprojects, we need to setup two aspects. First, the projects that run the tests and collect the code coverage data:

list/build.gradle

    plugins {
        id 'java-library'
        id 'jacoco'
    }

    dependencies {
        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.1'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
    }

list/build.gradle.kts

    plugins {
        `java-library`
        `jacoco`
    }

    dependencies {
        testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
        testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
    }

Whether you apply the plugin directly to all subprojects and make use of a `subprojects {}` block is up to you.

The build is setup to run tests using JUnit5 and we apply the `jacoco` plugin to collect the code coverage. With the plugin applied, it automatically attaches itself to the `test` task to collect the code coverage. Please refer to the JaCoCo chapter for more details on the plugin configuration.

Second, to generate a report spanning all our tested projects, we introduce a new task on the root project (or an aggregator subproject if you like) that takes care of setting up the reports, where jacoco can find the source files and which projects to collect the coverage data from.

build.gradle

    // task to gather code coverage from multiple subprojects
    // NOTE: the `JacocoReport` tasks do *not* depend on the `test` task by default. Meaning you have to ensure
    // that `test` (or other tasks generating code coverage) run before generating the report.
    // You can achieve this by calling the `test` lifecycle task manually
    // $ ./gradlew test codeCoverageReport
    tasks.register("codeCoverageReport", JacocoReport) {
        // If a subproject applies the 'jacoco' plugin, add the result it to the report
        subprojects { subproject ->
            subproject.plugins.withType(JacocoPlugin).configureEach {
                subproject.tasks.matching({ t -> t.extensions.findByType(JacocoTaskExtension) }).configureEach { testTask ->
                    sourceSets subproject.sourceSets.main
                    executionData(testTask)
                }

                // To automatically run `test` every time `./gradlew codeCoverageReport` is called,
                // you may want to set up a task dependency between them as shown below.
                // Note that this requires the `test` tasks to be resolved eagerly (see `forEach`) which
                // may have a negative effect on the configuration time of your build.
                subproject.tasks.matching({ t -> t.extensions.findByType(JacocoTaskExtension) }).forEach {
                    rootProject.tasks.codeCoverageReport.dependsOn(it)
                }
            }
        }

        // enable the different report types (html, xml, csv)
        reports {
            // xml is usually used to integrate code coverage with
            // other tools like SonarQube, Coveralls or Codecov
            xml.enabled true

            // HTML reports can be used to see code coverage
            // without any external tools
            html.enabled true
        }
    }

build.gradle.kts

    // task to gather code coverage from multiple subprojects
    // NOTE: the `JacocoReport` tasks do *not* depend on the `test` task by default. Meaning you have to ensure
    // that `test` (or other tasks generating code coverage) run before generating the report.
    // You can achieve this by calling the `test` lifecycle task manually
    // $ ./gradlew test codeCoverageReport
    tasks.register<JacocoReport>("codeCoverageReport") {
        // If a subproject applies the 'jacoco' plugin, add the result it to the report
        subprojects {
            val subproject = this
            subproject.plugins.withType<JacocoPlugin>().configureEach {
                subproject.tasks.matching({ it.extensions.findByType<JacocoTaskExtension>() != null }).configureEach {
                    val testTask = this
                    sourceSets(subproject.sourceSets.main.get())
                    executionData(testTask)
                }

                // To automatically run `test` every time `./gradlew codeCoverageReport` is called,
                // you may want to set up a task dependency between them as shown below.
                // Note that this requires the `test` tasks to be resolved eagerly (see `forEach`) which
                // may have a negative effect on the configuration time of your build.
                subproject.tasks.matching({ it.extensions.findByType<JacocoTaskExtension>() != null }).forEach {
                    rootProject.tasks["codeCoverageReport"].dependsOn(it)
                }
            }
        }

        // enable the different report types (html, xml, csv)
        reports {
            // xml is usually used to integrate code coverage with
            // other tools like SonarQube, Coveralls or Codecov
            xml.isEnabled = true

            // HTML reports can be used to see code coverage
            // without any external tools
            html.isEnabled = true
        }
    }

Using the approach above using `subproject.plugins.withType(JacocoPlugin)` avoids any ordering issues as to when the plugin is applied to the subprojects. This is important as the `test` tasks need to be enhanced by the `JacocoPlugin` to generate reports for the coverage data. See also Task Configuration Avoidance for more information about delayed configuration.

Running the tests and generate the report:

    $ ./gradlew codeCoverageReport

    BUILD SUCCESSFUL
    10 actionable tasks: 10 executed

For more information, see Testing in Java project chapter.