Step-by-Step Guide to Implementing Kover for Kotlin Code Coverage

Om Parashar
6 min readApr 25, 2023

--

Are you tired of spending hours testing your code and wondering if you’ve missed something important? Look no further than unit testing! Unit tests are a crucial part of the software development process that give you the confidence to make changes to your existing codebase without unintentionally breaking anything.

But, how do you ensure that your codebase is adequately tested? That’s where Kover comes in. As one of the most popular code coverage tools for Kotlin, Kover measures code coverage and generates reports in either HTML or XML format through JVM test tasks.

In this article, we will not only explore the features of Kover, but also how to use it to its full potential. We’ll learn how to enable code coverage checks before every git commit or other git commands, create a GitHub Workflow that checks code coverage every time a push is made to a branch, and even run scripts based on the results of these coverage checks when performed as a GitHub Action. With these techniques, you can ensure that your codebase is thoroughly tested, reliable, and of the highest quality.

Using Kover with Gradle for Effective Code Coverage

When it comes to measuring code coverage and generating reports in Kotlin projects, Kover is one of the most popular choices. In this article, we’ll look at how to install and use Kover with Gradle to get the most out of it.

Adding the Dependency in the Project

First, let’s add the Kover dependency to our project by following these steps:

  1. In the project-level build.gradle.kts, add the following under the plugin DSL:
plugins {
id("org.jetbrains.kotlinx.kover") version "0.6.1"
}
  1. Under the subprojects DSL, apply the plugin:
apply(plugin = "org.jetbrains.kotlinx.kover")
  1. Inside the subprojects DSL, apply the Kover plugin and add a rule:
kover {
verify {
rule {
isEnabled = true
name = "Coverage must be more than 60%"
bound {
minValue = 60
}
}
}
}

After building the code, a koverVerify task will appear in the Gradle tasks list. You can use the command ./gradlew koverVerify to run this task. If you want to run coverage checks for a specific module, use ./gradlew :module_name:koverVerify.

Excluding Specific Files and Generating Reports

In some cases, you may want to exclude certain files from the total coverage calculations. To exclude such files, define filters as follows:

kover {
filters {
classes {
excludes += listOf("*di.*", "*Factory*")
}
annotations {
excludes += listOf("*Generated", "*CustomAnnotationToExclude")
}
}
verify {
rule {
isEnabled = true
name = "Line Coverage of Tests must be more than 80%"
bound {
minValue = 60
}
}
}
}

Here, we’ve defined two different filters: Class and Annotations. Class filters are used to exclude lines in a class identified by the given pattern string. Annotation filters are used to exclude lines in classes or functions decorated with an annotation identified by the specified pattern string. You can use the excludes and includes lists to include or exclude specific classes or methods.

Now that we have configured Kover to calculate coverage according to our needs, let’s generate HTML or XML reports for better visibility of what is covered and what is not:

kover {
filters {
classes {
excludes += listOf("*di.*", "*Factory*")
}
annotations {
excludes += listOf("*Generated", "*CustomAnnotationToExclude")
}
}
htmlReport {
onCheck.set(false)
}
verify {
rule {
isEnabled = true
name = "Line Coverage of Tests must be more than 80%"
bound {
minValue = 60
}
}
}
}

After building the project, a koverHtmlReport task will appear in the Gradle tasks list. Use the command ./gradlew koverHtmlReport to generate an HTML report for your entire project. The report displays as a web page with lines colored in green or red to indicate whether the line was covered in test cases or not.

Configure Git hooks for git events

When you’re working on a project with a team, it’s essential to ensure that everyone on the team is adhering to the same code quality standards. One way to do this is to enforce code coverage requirements before any code is pushed to the repository.

Configuring Git pre-push hook to verify test coverage

A Git pre-push hook is a script that runs before a push is made to the repository. This hook can be used to enforce code coverage requirements by running the coverage check before allowing the push to proceed. Here’s how to set up a Git pre-push hook using Kover:

  1. Navigate to the project_dir/.git/hooks/ directory in your terminal.
  2. Replace the content of the pre-push.sample file with the following bash script:
#!/bin/bash

./gradlew koverVerify
if [[ $? -eq 0 ]]; then
echo "Test coverage: OK"
exit 0
else
echo "Test Coverage: FAILED."
exit 1
fi

The script first runs the koverVerify task using Gradle. If the task completes successfully (i.e., if the code coverage meets the requirements), the script exits with a 0 status code, allowing the push to proceed. Otherwise, the script exits with a non-zero status code, preventing the push from completing.

  1. Remove the .sample file extension from the pre-push.sample file.

With this hook in place, any team member attempting to push code to the repository will be blocked from doing so if the code coverage doesn’t meet the requirements.

Set up GitHub Workflow

In addition to running code coverage checks before allowing code to be pushed to the repository, you can also set up GitHub Workflows to automatically check code coverage every time a push is made to a branch.

Setting up GitHub Actions to perform at every PR

  1. Create a new CI action for Java with Gradle build.
  2. Use the following code to run test coverage and run a script if the task fails:
name: Test Coverage Check
on:
pull_request:
branches: [ "master" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: Test Coverage
id: test_coverage_step
continue-on-error: true
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
with:
arguments: koverVerify
- name: Notify Coverage Failure
if: steps.test_coverage_step.outcome != 'success'
run: sh ./scripts/notify_failure.sh

The workflow runs a job named build that:

  1. Checks out the code from the repository.
  2. Sets up the JDK 11 environment.
  3. Runs the koverVerify Gradle task.
  4. If the task fails, runs a script to notify team members that the code coverage check has failed.

With this GitHub Workflow in place, any push to the repository will automatically trigger a code coverage check. If the check fails, team members will be notified of the failure, allowing them to take corrective action as necessary.

Additional Ideas

  1. Use Kover in conjunction with other testing tools and frameworks to improve the quality and coverage of your tests.
  2. Integrate Kover with CI/CD pipelines to enforce code coverage requirements for all code changes.

Conclusion

In this article, we explored how to use Kover with Gradle to measure code coverage in Kotlin projects. We learned how to add the Kover dependency to our Gradle project, configure Kover to calculate coverage according to our needs, and generate HTML or XML reports for better visibility. Additionally, we looked at how to enable code coverage checks before every git commit or other git commands, create a GitHub Workflow that checks code coverage every time a push is made to a branch, and even run scripts based on the results of these coverage checks when performed as a GitHub Action.

With these techniques, you can ensure that your codebase is thoroughly tested, reliable, and of the highest quality. Kover is an incredibly useful tool that can help you take your testing practices to the next level, and integrating it into your workflow can greatly improve your productivity and confidence in the quality of your code.

References

  1. Kover GitHub Repository
  2. Git Hooks
  3. GitHub Actions Documentation

Also Check out

Unlocking the Power of Jackson: Custom Serializers and Deserializers in Java/Kotlin

--

--

Om Parashar
Om Parashar

Written by Om Parashar

Exploring Backend using Kotlin, Ruby, Python. Sharing insights from professional work and personal tech projects.

Responses (2)