Mockk: Cannot mockkstatic for Kotlin companion object static method

Created on 9 Sep 2018  路  11Comments  路  Source: mockk/mockk

Expected Behavior

I try to mock static method using mockkStatic(). It seems that mockkStatic() only works with two cases.

1. Pure Java Static Class

public class UtilJava {

    static String ok() {
        return "UtilJava ok()";
    }
}

2. Kotlin Object

object UtilKotlin {

    @JvmStatic
    fun ok(): String {
        return "UtilKotlin ok()"
    }

}

Usage

class Util {
    fun ok() {
        UtilJava.ok()
        UtilKotlin.ok()
    }
}

Test Code

class UtilTest {
    @Test
    fun ok() {
        // Given
        val util = Util()
        mockkStatic(UtilJava::class)
        mockkStatic(UtilKotlin::class)

        every { UtilJava.ok() } returns "Joe"
        every { UtilKotlin.ok() } returns "Tsai"

        // When
        util.ok()

        // Then
        verify { UtilJava.ok() }
        verify { UtilKotlin.ok() }

        assertEquals("Joe", UtilJava.ok())
        assertEquals("Tsai", UtilKotlin.ok())
    }
}

Current Behavior

Above code works pretty good, but it doesn't work with Kotlin companion object.

 class UtilKotlin {

    companion object {
        @JvmStatic
        fun ok(): String {
            return "UtilKotlin ok()"
        }
    }
}

Same test as above will throw this exception:
io.mockk.MockKException: Missing calls inside every { ... } block. on this line every { UtilKotlin.ok() } returns "Tsai"

Is there any way to mock companion object? Thanks!

Most helpful comment

I believe that in this scenario, as the calls are delegated to the companion object, you should mock the object itself using mockkObject.

class UtilTest {
    @Test
    fun ok() {
        // Given
        val util = Util()
        mockkStatic(UtilJava::class)
        mockkObject(UtilKotlin)

        every { UtilJava.ok() } returns "Joe"
        every { UtilKotlin.ok() } returns "Tsai"

        // When
        util.ok()

        // Then
        verify { UtilJava.ok() }
        verify { UtilKotlin.ok() }

        assertEquals("Joe", UtilJava.ok())
        assertEquals("Tsai", UtilKotlin.ok())
    }
}

I'm not sure if the behavior should be different tho. This provides a workaround specifically for kotlin objects, at least.

All 11 comments

Just a quick guess. Have you tried this:

  mockkStatic(UtilJava::class) 
  mockkStatic(UtilKotlin.Companion::class)

@oleksiyp I tried it, but still getting same exception.

io.mockk.MockKException: Missing calls inside every { ... } block.

I believe that in this scenario, as the calls are delegated to the companion object, you should mock the object itself using mockkObject.

class UtilTest {
    @Test
    fun ok() {
        // Given
        val util = Util()
        mockkStatic(UtilJava::class)
        mockkObject(UtilKotlin)

        every { UtilJava.ok() } returns "Joe"
        every { UtilKotlin.ok() } returns "Tsai"

        // When
        util.ok()

        // Then
        verify { UtilJava.ok() }
        verify { UtilKotlin.ok() }

        assertEquals("Joe", UtilJava.ok())
        assertEquals("Tsai", UtilKotlin.ok())
    }
}

I'm not sure if the behavior should be different tho. This provides a workaround specifically for kotlin objects, at least.

@Kerooker Thanks man! Even though mockkObject() is not intuitive to mock static method, it works like a charm. Besides, mockkObject(UtilKotlin.Companion) also works.

Delegating to the companion object makes everything clear. However, I just wonder which scenario I can use mockkstatic() except those two cases I mention above?

mockkStatic can be used to mock extension methods

@joetsaitw
MockkObject should become intuitive if you believe you're mocking the whole companion object, so Mocking Object for short :P

mockkObject(UtilKotlin.Companion) also works, because the compiler actually translates mockkObject(UtilKotlin) to mockkObject(UtilKotlin.Companion), so they're the same thing

@oleksiyp @Kerooker
Thanks a lot. It's clear to me now!

Please consider adding this example of mocking a companion object to the documentation. Or really just a mention of companion objects in the existing mock objects section. It might help others understand the usage.

For people like me.
Be sure you mock your object before calling a method that works with this object.
That was my problem.

I am writing unit test case for following class in Kotlin object class.

object DeviceUtils {

    fun getManufacture() = Build.MANUFACTURER.toLowerCase()
}

Test case:

@Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
        PowerMockito.mockStatic(DeviceUtils::class.java)
        subject = PowerMockito.spy(DeviceUtils)

        PowerMockito.`when`(subject.getManufacture()).then { "samsung" }
    }

I've tried with different solutions but no luck.

Can you guys please help me on same.

You're using mockito/powermock, and not mockk!

If you want to use mockk, take a look at the documentation of mockkObject

Was this page helpful?
0 / 5 - 0 ratings