Mockk允许模拟静态函数,但如何模拟 Kotlin 顶级函数?
例如,如果我有一个名为 的 Kotlin 文件HelloWorld.kt
,我如何模拟该sayHello()
函数?
你好世界.kt
fun sayHello() = "Hello Kotlin!"
有办法模拟一个顶级函数:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
你只需要知道这个函数去哪个文件。签入 JAR 或堆栈跟踪。
以下语法对我有用。
mockkStatic(::sayHello.javaMethod!!.declaringClass.kotlin)
我很惊讶目前还没有任何东西jvm-stdlib
。
编辑: 此重载现已正式引入: https ://github.com/mockk/mockk/pull/518
mockkStatic(::sayHello)
要添加以前的答案,这是可行的:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
其中 mockStatic 将“package_name:class_file_name”作为参数但是为了简化 mockStatick 调用,您可以直接在文件中使用 @file:JvmName 为您的文件命名。
你好世界.kt
@file:JvmName("hello")
fun sayHello() = "Hello Kotlin!"
HelloWorldTest.kt
mockkStatic("pkg.hello")
every { fun() } returns 5
关于为什么这是必要的和其他示例的更详细说明:https ://blog.kotlin-academy.com/mocking-is-not-rocket-science-mockk-advanced-features-42277e5983b5
基于@Sergey 的回答:
您可以将sayHello()
函数的实际实现放在一个变量中,该变量是函数参数的默认值sayHello()
。
这个例子有效:
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")
}
}
这样做的问题是您更改生产代码只是为了迎合测试,而且感觉很做作。
此代码不适用于 mockk 版本 1.10.0 但在 1.11.0 中运行良好(当然需要更改 mockkStatic(::bar) )
实用程序.kt
@file:JvmName("UtilsKt")
package com.example.myapplication
fun foo(): Boolean {
return bar()
}
fun bar():Boolean {
return false
}
测试
@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())
}
}