DEV Community

Patrick Charles Höfer
Patrick Charles Höfer

Posted on

3 1

MockK - nifty mock features I recently discovered

I am using MockK (https://mockk.io/) for a while now in all my Kotlin applications. But just recently I discovered some features I wish I knew beforehand because they really reduce the verbosity of my unit test.

As a developer I am lazy. Therefore I just looked up MockK features I needed at the time without discovering all the other mentioned advanced features. I felt like I will find them when I need them. To be honest - I should have spent some time reading the documentation. Next time I definitely will!

Here is a simple example that improved in readability thanks to some research on MockK features.

Logic to Test

Here is the logic I wanted to test

    fun dispatchEvent() {
        val taskPayload = Json.encodeToString(TaskPayload("123"))
        val gameEvent: GameEvent = GameEvent(UUID.randomUUID().toString(), "task", DateTime.now(), taskPayload)
        val topic = "projects/barbarus-game/topics/task"
        LOG.info("dispatch event to topic $topic")
        pubSubTemplate.publish(topic, gameEvent).addCallback({ LOG.info(it) }, { LOG.error("failure") })
    }
Enter fullscreen mode Exit fullscreen mode

Unit Test Iteration #0

And here is my initial unit test:

    internal class EventDispatcherTest {
    private val pubSubTemplate: PubSubTemplate = mockk()
    private val eventDispatcher: EventDispatcher = EventDispatcher(pubSubTemplate)

    @Test
    fun `should publish game event message`() {
        val testTopic = "projects/barbarus-game/topics/task"

        every { pubSubTemplate.publish(eq(testTopic), any<GameEvent>()) } returns mockk() {
            every { addCallback(any(), any()) } returns Unit
        }

        eventDispatcher.dispatchEvent()

        verify { pubSubTemplate.publish(eq(testTopic), any<GameEvent>()) }
    }
}
Enter fullscreen mode Exit fullscreen mode

I simply want to see if the dispatchEvent() function does call the PubSubTemplate#publish function as expected.

However MockK#verify does not work withou the pubSubTemplate mock being defined with a proxy. To satisfy the test runner I added an every for pubSubTemplate and also had to satisfy the return value (or answer in mockk-domain language). The return value is of type ListenableFuture. However I do not need any specific behaviour from it so I just mocked it away.

[...] returns mockk() {
            every { addCallback(any(), any()) } returns Unit
        }

Enter fullscreen mode Exit fullscreen mode

This is the part where I mock the ListenableFuture.

All of that I had to do, to simply just use verify and assert that my dispatchEvent function is calling the PubSubTemplate#$publish function with the expected topic string.

I did a quick google research to see what I can do better.

Unit Test Iteration #1

The first thing I was wondering about was, if there is a MockK idiomatic way to mock a function that returns Unit.

And I found this sweet article/documentation:

https://notwoods.github.io/mockk-guidebook/docs/mockito-migrate/void/

So instead of using returns Unit one can simply replace every with justRun.

The statement now looks a bit slicker

        every { pubSubTemplate.publish(eq(testTopic), any<GameEvent>()) } returns mockk() {
            justRun { addCallback(any(), any()) }
        }
Enter fullscreen mode Exit fullscreen mode

But wait! There is more!

Unit Test Iteration #2

So still I am unhappy with verify being dependant on the every mock of pubSubTemplate. I then stumbled over https://mockk.io/#relaxed-mock

I had no idea what "relaxed" might imply in the context of unit testing. So I took a little research. It says "allows creation with no specific behaviour". So all functions are returning "Simple Values" by default - so me as a developer doesn't need to implement a behaviour with every for the called functions of that unit under test.

The only thing I needed to do was to call the mockk() function with relaxed = true argument.


internal class EventDispatcherTest {
    private val pubSubTemplate: PubSubTemplate = mockk(relaxed = true)
    private val eventDispatcher: EventDispatcher = EventDispatcher(pubSubTemplate)

    @Test
    fun `should publish game event message`() {
        val testTopic = "projects/barbarus-game/topics/task"
        eventDispatcher.dispatchEvent()
        verify { pubSubTemplate.publish(eq(testTopic), any<GameEvent>()) }
    }
}
Enter fullscreen mode Exit fullscreen mode

And voila the simple verify assertion does it job without the need of a behaviour definition of the mocked class.

Final Words

I hope I could help one or two developers with this. I'd wish I knew it earlier but hey - better now than never eh?

Sentry mobile image

Mobile Vitals: A first step to Faster Apps

Slow startup times, UI hangs, and frozen frames frustrate users—but they’re also fixable. Mobile Vitals help you measure and understand these performance issues so you can optimize your app’s speed and responsiveness. Learn how to use them to reduce friction and improve user experience.

Read the guide →

Top comments (0)

Sentry mobile image

Improving mobile performance, from slow screens to app start time

Based on our experience working with thousands of mobile developer teams, we developed a mobile monitoring maturity curve.

Read more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay