During unit testing, our goal is to segregate each part of the program and test its functionality. The problem occurs when certain parts of the code remain uncovered by the test. It can lead to several issues, including potential code defects in the production app. We may try to locate those untested parts manually, but at some point, this will become impossible and not cost-effective at all. Code coverage tool can make this process simple and allow us to perform this kind of analysis automatically. By running the code coverage, we can check which part of the code was called by the test and visualize an overall percentage of the covered code. The more we cover our code, the less we will encounter a defect in the production app.
What is JaCoCo?
JaCoCo is a free code coverage library for Java, which has been created by the EclEmma team based on the lessons learned from using and integration existing libraries for many years. This toolkit is very popular among other code coverage framework out there. JaCoCo works by measuring lines and branch coverage performed by the Unit test. It can show a visual report with detailed insight into code coverage. It includes the number of covered lines and the total percentage of executed code in each method. Based on the generated report, the developer can evaluate which part of the code needs more attention. Also, they can focus on the areas where the level of the test is low.
Why should you use JaCoCo?
- Supports multi-module, multi-flavored project.
- You can define an inclusion/exclusion list for files.
- Provides a detailed breakdown of the report. E.g., which function has what number of coverage percentage.
- Option to export the report in XML, CSV or HTML format.
- Beautiful code highlights for un-tested code.
Our test Android project has one Java module (domain) and one Android module (data). We will create a Gradle script to configure the JaCoCo setup. This script will contain all the necessary logic to run the test and generate a report. Since we will cover a multi-module, multi-flavored project, our script will take care of it.
Go to the root directory of the project and create a new sub-directory “tools“. Inside the “tools” directory, create a new empty file called “script-jacoco.gradle”. Now go to the Android Studio and change the display perspective to “Project” from “Android”. You will get the option at the top left corner of the screen. Right beside the “Project” sidebar. Now open the newly created jaCoCo script file.
The script has several parts, so let’s break it down into multiple pieces. First, let’s try to identify if it’s an Android or Java project. The is useful to apply different logic based on the module type. This function will return a boolean to verify if the project is Java or an android module.
The next part of the code will execute when we run the test coverage. It checks the project type based on the function we wrote earlier and calls the appropriate setup.
This function is suitable for Java-based projects only. It has some basic configuration for the JaCoCo test. Including the report output format and destination file. Also, it has an “afterEvaluate” block, which excludes certain classes from the coverage.
The last part of the script contains the configuration for the Android-based project.
- Dynamically add “jacoco.includeNoLocationClasses true” to each test
- Get all build types (debug, release)
- Get all product flavors (app, beta, prod)
- When no product flavors are available, add an empty flavor
- For each product flavor, loop through all of its build types
- Dynamically create JaCoCo tasks based on the product flavor
- Define the file filter and source location for Java and Kotlin class
- Configure how the coverage will output the result
The final script will look like this:
We are almost there. Let’s add the JaCoCo dependency first to our root-level “build.gradle” file.
Now we need to add the script to all of our project-level “build.gradle” files, Including the “build.gradle” file for modules.
We are all good to go. Now, to run the code coverage, use the following commands:
./gradlew app:testAppDebugUnitTestCoverage // app Flavor./gradlew app:testBetaDebugUnitTestCoverage // beta Flavor./gradlew app:testProdDebugUnitTestCoverage // prod Flavor
If everything goes well and all of your tests passes, JaCoCo will generate a report in the following location:
After going to the directory and opening the “index.html” file in our browser, we can see the following results.
Measuring unit test coverage in multi-module Android projects using Jacoco
Не так давно наша команда решила всерьез заняться unit-тестированием на проекте. На самом деле, у нас уже была практика…