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())
}
}
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!
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
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.I'm not sure if the behavior should be different tho. This provides a workaround specifically for kotlin objects, at least.