SonarQube code coverage for Kotlin on Android with Bitrise

You have a Kotlin Android app and you want SonarQube code coverage reports? Peter-John Welcome found a way. Read his guide.

You have a Kotlin Android app and you want SonarQube code coverage reports? Peter-John Welcome found a way. Read his guide.

Guest post by Peter-John Welcome, the original post appeared on AndroidPub.

Peter-John is a mobile developer at Dynamic Visual Technologies, developing a banking app for one of South Africa’s biggest banks. He works on both Android and iOS platforms and enjoys using new technologies and APIs. Big Kotlin and Swift fan. In his spare time, he's into photography, blogging about technology and co-organising developer meetups at GDG Johannesburg.

I’ve recently been working on an Android app that is 100% Kotlin with a full development CI pipeline. Having a good app means that the code is testable, which led me to use SonarQube for static code analysis and code coverage.

Since there is no official Kotlin plugin for SonarQube yet, I looked at a third party plugin on GitHub named Sonar-Kotlin. This plugin is awesome as it has another library called detekt integrated into it. Detekt is what does the static code analysis. What about the code coverage you ask? Well, the Sonar-Kotlin plugin has the ability to give us code coverage reports, but there is some set up that needs to be done.

This is where my journey with SonarQube code coverage began, with my Android app written in Kotlin.

This post assumes you have SonarQube setup and some kind of CI.

Getting Started

Getting the Sonar-Kotlin plugin installed is very simple. I have a VM running on Google Compute Engine that has SonarQube installed in a Docker container. Then pretty much followed the steps on the plugin's Github page and it was installed.

  • git clone https://github.com/arturbosch/sonar-kotlin
  • cd sonar-kotlin
  • ./gradlew build
  • cp build/libs/sonar-kotlin-[enter_version].jar $SONAR_HOME/extensions/plugins
  • $SONAR_HOME/bin/[your_os]/sonar.sh restart

The CI I’m using for the project is Bitrise. This is a pretty awesome CI for its workflow editor and all its third-party integrations. One of those third party tools Bitrise provides is Sonarqube scanner.

Editor's note: the SonarQube Scanner step was written by @koral of DroidsOnRoids as a community contribution. Thanks for it. 🙂

Within Bitrise we will add our scanner properties so when the SonarQube scanner build step is invoked, those properties will be executed accordingly.


sonar.sources=.
  sonar.login=$SonarToken
  sonar.projectKey=$BITRISE_APP_TITLE
  sonar.host.url=$SonarUrl
  sonar.report.export.path=sonar-report.json
  detekt.sonar.kotlin.config.path=default-detekt-config.yml
  sonar.java.binaries=target/classes
  sonar.sources=app/src/main/java
  sonar.tests=app/src/test/java
  sonar.java.coveragePlugin=jacoco
  sonar.jacoco.reportPaths=app/build/jacoco/testDebugUnitTest.exec
Copy code

So for us to get a sonar code coverage report for Java code, we need to have a gradle task that will generate a Jacoco report. This is the same for Kotlin.

I found this article to help you get started with Jacoco.

Once we have that set up within our workflow, we need to run the following gradle command before the SonarQube scanner task runs:


./gradlew clean jacocoTestReport
Copy code

The scanner needs a Jacoco report to show code coverage in SonarQube and the command above provides that for us.



If we run a build now, we will see the following SonarQube report:


As seen above, we do not have code coverage, even though I said at the beginning that the plugin supports code coverage for kotlin code.

This is due to the Kotlin class files not being generated in the same location as Java class files. For us to get around this, we need to add the location of the Kotlin class files to the sonar.java.binaries property.


sonar.java.binaries=target/classes,app/build/tmp/kotlin-classes
Copy code

This location can differ depending on your project. We need to keep the “target/classes” in order for the Java class files to be picked up as well.

We then run our CI build again and we get code coverage for our Kotlin code.



A lot of experimenting was done to get to this point. There is not much help out there in getting this work, which is the reason for me sharing my experience. I hope this helps everyone out there who is trying to solve the same problem I had.

Happy SonarQube code coverage.

No items found.
The Mobile DevOps Newsletter

Explore more topics

App Development

Learn how to optimize your mobile app deployment processes for iOS, Android, Flutter, ReactNative, and more

Bitrise & Community

Check out the latest from Bitrise and the community. Learn about the upcoming mobile events, employee spotlights, women in tech, and more

Bitrise Insights

Cache | Caching

Mobile App Releases

Learn how to release faster, better apps on the App Store, Google Play Store, Huawei AppGallery, and other app stores

Mobile DevOps

Learn Mobile DevOps best practices such as DevOps for iOS, Android, and industry-specific DevOps tips for mobile engineers

Mobile Testing & Security

Learn how to optimize mobile testing and security — from automated security checks to robust mobile testing and more.

Product Updates

Check out the latest product updates from Bitrise — Build Insights updates, product news, and more.

The Mobile DevOps Newsletter

Join 1000s of your peers. Sign up to receive Mobile DevOps tips, news, and best practice guides once every two weeks.