blog podcast

Mocking and Kotlin

One of the good things with Kotlin is it’s accessible interoperability with Java. Being a new language though it has made some design decisions that are different from Java’s which sometimes can create boundaries in the usage across language boundaries and one of these decisions is what I want to talk about today.

In Java every class, and every function in this class, is by default extendible. You have to explicitly state that it is sealed to make it non extendible. Now, in Kotlin they wanted another route. They chose to say that nothing is extendible unless you explicitly mark it as open. Although I can’t look into the head of the language designers I believe this choice was made because inheritance in general is something that can easily backfire, and with the feature of Extension Methods there really isn’t too great of a need of overwriting unexpected methods.. Unless you happen to be Mockito and want to mock something.

Baeldung has written an Article on mocking and mockito. It uses an Interface though which of course is extendible. If you want to mock a class you have to make sure that the class is open and the function you want to extend in open. What happens otherwise? If the class isn’t open you’ll get a straight up exception saying it can’t be extended. If the method is not open you won’t get an exception, but the method ends up not being mocked, meaning it will try to run the real code, which in a mock proxy likely can end up with a NullPointerException since no instance variables will have been initialize by default.

Code of the Day

To help you with things that needs to be proxied (like for example mocks, but also Controllers or other framework code that wants to do some magic), Gradle has some plugin support that will automatically mark your class and its methods as open.

plugins {
    id 'org.jetbrains.kotlin.jvm' version "1.5.0"
    id "org.jetbrains.kotlin.plugin.allopen" version "1.5.0"
}

...

allOpen {
    annotation("javax.ws.rs.Path")
    annotation("javax.enterprise.context.ApplicationScoped")
    annotation("io.quarkus.test.junit.QuarkusTest")
}

The above are excerpts from a build.gradle file. Classes that are marked with the mentioned Annotations in allOpen will automatically get all functions marked as open. This is needed by Quarkus to be able to manage beans. If we would have been coding Spring we would likely have put the Component annotation in here.