Debugging mocked Kotlin objects

The Caplin Integration Team has recently started creating our latest set of adapters used for internal testing and demos.

For this version of our mock adapters we opted to go with Kotlin as our primary language. This has however introduced some rather interesting issues when testing.

One of the perks of using Kotlin is that we can use java classes, which for testing allowed us to use Mockito. During testing, we started noticing some oddities. All code examples and debugging sessions are done using IntelliJ.

To demonstrate our issues, first a bit of background. Consider a very simple class like:

class Lamp {
    private boolean isLampOn;

    public boolean isLampOn(){
        return isLampOn;
    }
}

Written in Kotlin this class would be written like:

class Lamp{
    var isLampOn = false
}

In Kotlin we do not have to explicitly create getters and setters for private fields in classes, we could simply access a Lamp objects variable using lamp.isLampOn for both reading and writing.

What happens is that Kotlin generates getters and setters for us whilst letting us access the fields in a way that looks like the field was public (it is private by default).

Now supposed we want to write tests for that class in java:

@Test
public void testLamp(){
    Lamp lamp = Mockito.mock(Lamp.class);
    when(lamp.isLampOn()).thenReturn(true);
    //Do more things
}

If we add a breakpoint on a line after the when() and run an evaluation on lamp.isLampOn() it would evaluate to true, which is what we would expect. If we write the same test in Kotlin:

@Test
fun testLamp(){
    var lamp = Mockito.mock(Lamp::class.java)
    whenever(lamp.isLampOn).thenReturn(true)
    //Do more stuff
}

Add a breakpoint after the whenever (when is a reserved keyword in Kotlin hence the whenever).

Evaluate like we did before and it will return false rather than the mocked value. However if we were to do something like val result = lamp.isLampOn, result would equal true.

It seems that while using Mockito in Kotlin works rather well, debugging mocked objects in Kotlin is not as reliable as it is in Java.

If we were to change our Lamp class to override the getters and setters like:

class Lamp{
    var isLampOn = false
    get() = field
    set(value){
        field = value
    }
}

and re-run the exact same test, accessing the isLampOn field using lamp.isLampOn and evaluating the method, we will get true. This implies that the debugger is having issues resolving results of mocked implicit method calls on Kotlin objects.

For now Kotlin is proving a pleasant language to code in but there are some issues, like the one above, that one should be mindful of.

Leave a Reply

Your e-mail address will not be published. Required fields are marked *