你如何模拟 Kotlin 顶级函数?
How do you Mockk a Kotlin top level function?
Mockk 允许模拟静态函数,但如何模拟 Kotlin 顶级函数?
例如,如果我有一个名为 HelloWorld.kt
的 Kotlin 文件,我该如何模拟 sayHello()
函数?
HelloWorld.kt
fun sayHello() = "Hello Kotlin!"
基于@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")
}
}
这样做的问题是,您更改生产代码只是为了满足测试需求,感觉做作。
有办法模拟顶级函数:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
你只需要知道这个函数去哪个文件就可以了。签入 JAR 或堆栈跟踪。
要添加以前的答案,这是有效的:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
其中 mockStatic 作为参数 "package_name:class_file_name"
但是为了简化 mockStatick 调用,您可以直接在文件中使用 @file:JvmName 为编译器命名文件。
HelloWorld.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
以下语法对我有用。
mockkStatic(::sayHello.javaMethod!!.declaringClass.kotlin)
令我惊讶的是 jvm-stdlib
上还没有任何内容。
编辑:
现在官方已经引入了这个重载:
https://github.com/mockk/mockk/pull/518
mockkStatic(::sayHello)
此代码不适用于 mockk 版本 1.10.0,但在 1.11.0 中运行良好(当然需要更改 mockkStatic(::bar) )
Utils.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())
}
}
Mockk 允许模拟静态函数,但如何模拟 Kotlin 顶级函数?
例如,如果我有一个名为 HelloWorld.kt
的 Kotlin 文件,我该如何模拟 sayHello()
函数?
HelloWorld.kt
fun sayHello() = "Hello Kotlin!"
基于@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")
}
}
这样做的问题是,您更改生产代码只是为了满足测试需求,感觉做作。
有办法模拟顶级函数:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
你只需要知道这个函数去哪个文件就可以了。签入 JAR 或堆栈跟踪。
要添加以前的答案,这是有效的:
mockkStatic("pkg.FileKt")
every { fun() } returns 5
其中 mockStatic 作为参数 "package_name:class_file_name" 但是为了简化 mockStatick 调用,您可以直接在文件中使用 @file:JvmName 为编译器命名文件。
HelloWorld.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
以下语法对我有用。
mockkStatic(::sayHello.javaMethod!!.declaringClass.kotlin)
令我惊讶的是 jvm-stdlib
上还没有任何内容。
编辑: 现在官方已经引入了这个重载: https://github.com/mockk/mockk/pull/518
mockkStatic(::sayHello)
此代码不适用于 mockk 版本 1.10.0,但在 1.11.0 中运行良好(当然需要更改 mockkStatic(::bar) )
Utils.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())
}
}