Kotlin + JaCoCo: Tuning Compiler to Skip Generated Code.

Update Sep/18: starting from version 0.8.2 JaCoCo has a bunch of new features for filtering out generated code. See changelog for more details: https://www.jacoco.org/jacoco/trunk/doc/changes.html

JaCoCo is a free and powerful library for generating comprehensive test coverage reports. Unfortunately for Kotlin developers the collected test information may appear unreadable and dirty.

There are two reasons for that:

  • Kotlin compiler generates a lot of bytecode even for a concise syntactic constructions;
  • From JaCoCo’s point of view there is no difference between developer and compiler generated code — it analyzes everything in bytecode when composing coverage reports.

Coverage report for Kotlin Data Class.

For instance let’s compile and analyze simple Kotlin Data class shown below:

JaCoCo reports about quite poor coverage. Actually we don’t need to worry about that because all methods are silently produced by Kotlin compiler and their implementations are assumed to be infallible — in JetBrains we trust!

From the bytecode there is no any “stop sign” for coverage analyzer telling which part of code should be skipped.

JaCoCo 0.8.0 and @Generated annotation.

In release 0.8.0 a new filter was introduced to handle special annotation used by project Lombok. All methods annotated with @lombok.Generated are now ignored by JaCoCo analyzer.

Nevertheless, Kotlin compiler still has no idea about this awesome feature!

Kotlin fork on GitHub.

Here you can clone a fork of the original JetBrains repository with patched compiler. See detailed description and supported features inside:

Link: https://github.com/andreyfomenkov/kotlin

Skipping equals(), hashCode(), toString(), copy() and componentN() for Data Classes.

Here is a coverage result for the User data class, but with patched compiler. As you can see some generated methods are gone and report looks better:

Wow! Enhanced code coverage without actual writing any additional unit tests!

Just for comparison with the old report let me duplicate the image:

Skipping generated methods for lateinit properties.

The following class Foo contains late-initialized property bar:

Compiler creates getBar() / setBar() methods for the property:

That’s why JaCoCo again reports about uncovered code. What a pity!

Let’s run with the patched compiler, analyze and decompile:

Awesome! Methods related to lateinit property are thrown away!

Another example — lateinit property is now not marked as “uncovered”:

And how it was before:

Conclusion.

Code architecture in the original repository is very clear and well-organized, that’s why implementing another patches for the compiler should not turn into a big problem. Feel free to contribute and propose improvements!