AkshatP
AkshatP

Reputation: 564

Gradle Jacoco test coverage for integration test across sub modules

I am having my project structure as follows,

--Project
   --Dao
   --Service
   --Controller
       --test
       --build.gradle.kts

I am having only integration tests in the controllers. All my sub modules(DAO, Services and Controllers) are gradle projects with build.gradle.kts inside them.

Following is my build.gradle.kts in my parent module, i.e. inside Project

import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

val Project.`java`: JavaPluginConvention
    get() = convention.getPluginByName("java")

plugins {
    val kotlinVersion = "1.3.61"
    val testLoggerVersion = "1.6.0"
    val dokkaVersion = "0.9.18"

    base
    jacoco
    kotlin("jvm") version kotlinVersion apply false
    maven
    id("com.adarshr.test-logger") version testLoggerVersion apply false
    id("org.jetbrains.dokka") version dokkaVersion apply false
}

jacoco {
    toolVersion = jacocoVersion
    reportsDir = file("$buildDir/reports/jacoco")
}

allprojects {
    version = "dev"

    repositories {
        jcenter()
        mavenCentral()
    }
}

subprojects {
    apply {
        plugin("kotlin")
        plugin("jacoco")
        plugin("com.adarshr.test-logger")
        plugin("org.jetbrains.dokka")
    }

    dependencies {
        "implementation"(kotlin("stdlib"))
        "implementation"("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion")

        "implementation"("com.fasterxml.jackson.module:jackson-module-kotlin:$fasterxmlVersion")
        "implementation"("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$fasterxmlVersion")
        "implementation"("org.koin:koin-core:$koinVersion")

        "testImplementation"("org.koin:koin-test:$koinVersion")
        "testImplementation"("io.mockk:mockk:$mockkVersion")
        "testImplementation"("org.junit.jupiter:junit-jupiter-api:$jUnitVersion")
        "testImplementation"("org.junit.jupiter:junit-jupiter-params:$jUnitVersion")
        "testImplementation"("org.testcontainers:junit-jupiter:$testcontainersVersion")
        "testImplementation"("org.testcontainers:testcontainers:$testcontainersVersion")
        "testImplementation"("org.testcontainers:postgresql:$testcontainersVersion")
        "testRuntime"("org.junit.jupiter:junit-jupiter-engine:$jUnitVersion")
    }

    tasks.register<Jar>("uberJar") {
        archiveClassifier.set("uber")
        from(java.sourceSets["main"].output)

        dependsOn(configurations["runtimeClasspath"])

        from({
            configurations["runtimeClasspath"]
                .filter { it.name.endsWith("jar") }
                .map { zipTree(it) }
        })
    }

    tasks.register<Zip>("uberZip") {
        from(java.sourceSets["main"].output)

        dependsOn(configurations["runtimeClasspath"])
        from({
            configurations["runtimeClasspath"]
                .filter { it.name.endsWith("jar") }
                .map { zipTree(it) }
        })
    }

    tasks.withType<DokkaTask> {
        outputFormat = "html"
        outputDirectory = "$buildDir/javadoc"
    }

    tasks.withType<KotlinCompile> {
        sourceCompatibility = javaVersion
        targetCompatibility = javaVersion

        kotlinOptions {
            jvmTarget = javaVersion
            apiVersion = kotlinVersion
            languageVersion = kotlinVersion
        }
    }

    tasks.withType<JacocoReport> {
        reports {
            html.apply {
                isEnabled = true
                destination = file("$buildDir/reports/jacoco")
            }
            csv.isEnabled = false
        }

        afterEvaluate {
            classDirectories.setFrom(files(classDirectories.files.map {
                fileTree(it).apply {
                    exclude("io/company/common/aws/test/support/**")
                    exclude("io/company/common/system/**")
                }
            }))
        }
    }

    tasks.withType<Test> {
        useJUnitPlatform()
        testLogging.showStandardStreams = true
        testLogging {
            events("PASSED", "FAILED", "SKIPPED", "STANDARD_OUT", "STANDARD_ERROR")
        }
    }


}

My problem is for jacoco code coverage. When I run ./gradlew clean test jacocoTestReport I only get coverage for my controllers and not for services and daos.

My gradle version is 5.4.1.

How can I get a consolidate report for the test coverage, covering all the test modules ?? I have tried multiple links from stackoverflow, but had no luck.

Upvotes: 6

Views: 2668

Answers (1)

Arvid Heise
Arvid Heise

Reputation: 3634

You can use the JacocoMerge task for that, which was explicitly created for that use case. It will take the individual reports of the subprojects and merge them into one report. Add the following snippet to your root project and adjust where necessary.

val jacocoMerge by tasks.registering(JacocoMerge::class) {
    subprojects {
        executionData(tasks.withType<JacocoReport>().map { it.executionData })
    }
    destinationFile = file("$buildDir/jacoco")
}

tasks.register<JacocoReport>("jacocoRootReport") {
    dependsOn(jacocoMerge)
    sourceDirectories.from(files(subprojects.map {
        it.the<SourceSetContainer>()["main"].allSource.srcDirs
    }))
    classDirectories.from(files(subprojects.map { it.the<SourceSetContainer>()["main"].output }))
    executionData(jacocoMerge.get().destinationFile)
    reports { // <- adjust
        html.isEnabled = true
        xml.isEnabled = true
        csv.isEnabled = false
    }
}

Now a gradle jacocoRootReport will give you the overall coverage.

Upvotes: 1

Related Questions