Mockk allows mocking static functions, but how does one mock a Kotlin top level function?
For example, if I have a Kotlin file called HelloWorld.kt
, how do I mock the sayHello()
function?
HelloWorld.kt
fun sayHello() = "Hello Kotlin!"
Mockk allows mocking static functions, but how does one mock a Kotlin top level function?
For example, if I have a Kotlin file called HelloWorld.kt
, how do I mock the sayHello()
function?
HelloWorld.kt
fun sayHello() = "Hello Kotlin!"
The following syntax has worked to me.
mockkStatic(::sayHello.javaMethod!!.declaringClass.kotlin)
I'm surprised there is nothing on the jvm-stdlib
yet for this.
Edit: This overload has now been introduced officially: https://github.com/mockk/mockk/pull/518
mockkStatic(::sayHello)
There is way to mockk a top level function:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
You just need to know which file this function goes. Check in JAR or stack trace.
To add on previous answers this is working:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
Where mockStatic takes as an argument "package_name:class_file_name" But to simplify the mockStatick call you can give your file a name for the compiler with @file:JvmName directly in the file.
HelloWorld.kt
@file:JvmName("hello")
fun sayHello() = "Hello Kotlin!"
HelloWorldTest.kt
mockkStatic("pkg.hello")
every { fun() } returns 5
More detailed explication on why this is necessary and other examples here:https://blog.kotlin-academy.com/mocking-is-not-rocket-science-mockk-advanced-features-42277e5983b5
Building on @Sergey's answer:
You could have the actual implementation of the sayHello()
function in a variable that's then the default value of a function parameter to sayHello()
.
This example works:
package tests
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
val sayHelloKotlin = { "Hello Kotlin!" }
fun sayHello(producer: () -> String = sayHelloKotlin): String = producer()
class Tests {
interface Producer {
fun produce(): String
}
@Test
fun `Top level mocking`() {
val mock = mockk<Producer>()
every { mock.produce() } returns "Hello Mockk"
val actual = sayHello(mock::produce)
Assertions.assertEquals(actual, "Hello Mockk")
}
}
The problem with this is that you're changing production code just to cater for testing, and it feels contrived.
This code doesn't work for me with mockk version 1.10.0 but works well in 1.11.0 (of course need to change mockkStatic(::bar) )
Utils.kt
@file:JvmName("UtilsKt")
package com.example.myapplication
fun foo(): Boolean {
return bar()
}
fun bar():Boolean {
return false
}
Test
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1])
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
mockkStatic("com.example.myapplication.UtilsKt")
every { bar() } returns true
assertTrue(foo())
}
}