JaCoCo Configuration using Gradle’s Kotlin DSL

Recently I used Kotlin DSL for writing Gradle scripts in a spring boot project. As Gradle’s Kotlin DSL is quite new, the documentation and community support was less compared to the Groovy DSL. So I found it hard to configure JaCoCo for test coverage. In this blog I will share how I added test coverage in my project:

Before getting in to the implementation let me put down the requirements:

  1. A test task to run all unit tests
  2. A testCoverage task that run all unit tests, generate coverage report and run verification
  3. A way to ignore classes and files from coverage verification

1. A test task to run all unit tests

When using a JVM language plugin like Java in Gradle, a task called test is automatically provided. This task runs all tests under src/test by default.

We just have to add a config to run the tests using a test runner (JUnit in my case):

val test by tasks.getting(Test::class) {
useJUnitPlatform { }
}

2. A testCoverage task that run all unit tests, generate coverage report and verify the report

First we need to add the JaCoCo library by adding it in the plugins section:plugins {
...
jacoco
}
By default JaCoCo gives two tasks called jacocoTestReport and jacocoTestCoverageVerification for generating coverage report and running verification respectively.As I need only html report I added a jacocoTestReport config like this:tasks.jacocoTestReport {
reports {
xml.isEnabled = false
csv.isEnabled = false
html.isEnabled = true
html.destination = file("$buildDir/reports/coverage")
}
}

And I want to fail the task when the coverage falls below 90%. So I added a jacocoTestCoverageVerification like this:

tasks.jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = "0.9".toBigDecimal()
}
}
}
}

We can generate coverage report and run verification by doing:

./gradlew test jacocoTestReport jacocoTestCoverageVerification

It will be good if we have a wrapper task called testCoverage that runs test, jacocoTestReport and jacocoTestCoverageVerification . Lets add this new task:

val testCoverage by tasks.registering {
group = "verification"
description = "Runs the unit tests with coverage."

dependsOn(":test", ":jacocoTestReport", ":jacocoTestCoverageVerification")
val jacocoTestReport = tasks.findByName("jacocoTestReport")
jacocoTestReport?.mustRunAfter(tasks.findByName("test"))
tasks.findByName("jacocoTestCoverageVerification")?.mustRunAfter(jacocoTestReport)
}

Now to run we just have to do:

./gradlew testCoverage

3. A way to ignore classes and files from coverage verification

I want to ignore certain files and classes from the JaCoCo verification. To do that we can modify the classDirectories or sourceDirectories used by jacocoTestCoverageVerification task like this:

tasks.jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = "0.9".toBigDecimal()
}
}
}
classDirectories.setFrom(
sourceSets.main.get().output.asFileTree.matching {
// exclude main()
exclude("com/example/helloworld/ApplicationKt.class")
}
)
}

Now if we run ./gradlew testCoverage, main() function will be excluded from verification.

A full gradle script containing similar implementation is available here: spring-boot-helloworld.

Originally published at https://arunvelsriram.dev

Open Source | DevOps | Infrastructure | Backend | Ployglot Programmer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store