【问题标题】:Mocking extension function in KotlinKotlin 中的模拟扩展功能
【发布时间】:2021-01-11 20:56:13
【问题描述】:

如何在测试中使用 Mockito 或 PowerMock 模拟 Kotlin 扩展功能?由于它们是静态解析的,应该将它们作为静态方法调用还是非静态进行测试?

【问题讨论】:

  • 就像在 Java 中一样,您希望避免使用这样的静态方法。静态方法通常应该用作简单的 util 函数。扩展函数类似于静态方法,因此它们只能用作简单的 util 函数。这些函数应该非常简单,不需要也不值得模拟它们。
  • 你能提供你到目前为止所尝试的吗?
  • 只是想知道:您还在等待其他答案吗?或者我可以做些什么来让我的答案值得接受?

标签: unit-testing mocking mockito kotlin powermock


【解决方案1】:

我认为 MockK 可以帮助你。

它也支持模拟扩展功能

您可以使用它来模拟对象范围的扩展:

data class Obj(val value: Int)

class Ext {
    fun Obj.extensionFunc() = value + 5
}

with(mockk<Ext>()) {
    every {
        Obj(5).extensionFunc()
    } returns 11

    assertEquals(11, Obj(5).extensionFunc())

    verify {
        Obj(5).extensionFunc()
    }
}

如果你的扩展是一个模块范围的,这意味着它是在一个文件中声明的(而不是在class中),你应该用这种方式模拟它:

data class Obj(val value: Int)

// declared in File.kt ("pkg" package)
fun Obj.extensionFunc() = value + 5

mockkStatic("pkg.FileKt")

every {
    Obj(5).extensionFunc()
} returns 11

assertEquals(11, Obj(5).extensionFunc())

verify {
    Obj(5).extensionFunc()
}

通过添加 mockkStatic("pkg.FileKt") 行以及声明扩展名的包和文件的名称(示例中为 pkg.File.kt)。

更多信息可以在这里找到:web sitegithub

【讨论】:

  • 当扩展函数有参数时这是否有效?由于参数不匹配,验证似乎失败(奇怪的是,它似乎期待另一个参数,其类型等于您要扩展的类)
  • 完美运行,谢谢!请注意,当使用 verify 时,您需要使用来自 Mockk 库而不是来自 Mockito 的那个。由于我在同一个文件中,我通过创建导入别名来解决它:import io.mockk.verify as verifyMockk
  • 这对我没有用,但有一种稍微不同的方式(适用于示例):每个 { any().extensionFunc() } 返回 11 看起来很傻,因为现在结果确实如此不依赖于参数,但在我的用例中它不必,另一种方式是抛出错误。
【解决方案2】:

首先,Mockito 一无所知 Kotlin 特定的语言结构。最后,Mockito 将查看进入字节码。 Mockito 只能理解它在那里找到的东西以及看起来像 Java 语言结构的东西。

含义:确实,您可能想使用javap 来反汇编已编译的类文件,以识别您要模拟的方法的确切名称/签名。

显然:当该方法是静态时,您必须使用 PowerMock 或 JMockit;如果没有,您应该更喜欢使用 Mockito。

从 java 的角度来看,你只是避免模拟静态的东西;但是当然,事情变得非常有趣,因为具有不同想法/概念的不同语言聚集在一起。

【讨论】:

  • 只为下一个人,java中的扩展函数签名:class FilenameKt { public static ReturnType extensionName(Receiver receiver, Params otherParams)...
【解决方案3】:

在 mockito-kotlin 的帮助下,可以像这样对实例扩展函数进行存根和验证:

data class Bar(thing: Int)

class Foo {
   fun Bar.bla(anotherThing: Int): Int { ... }
}

val bar = Bar(thing = 1)
val foo = mock<Foo>()

with(foo) {
  whenever(any<Bar>().bla(any()).doReturn(3)
}

verify(foo).apply {
  bar.bla(anotherThing = 2)
}

【讨论】:

  • 正是我想要的!
  • 所以你必须将扩展函数包装在一个类中?
【解决方案4】:

我使用 mockk 库。

对于扩展文件写java名称,像这样:

@file:JvmName(name = "ExtensionUtils")

package myproject.extension

...

为了快速编码,我创建了具有不同扩展模拟的文件:

object FastMock {

    fun extension() = mockkStatic("myproject.extension.ExtensionUtils")

    fun listExtension() = mockkStatic("myproject.extension.ListExtensionUtils")

}

在测试中调用这个:

FastMock.listExtension()
every { itemList.move(from, to) } returns Unit

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2019-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    相关资源
    最近更新 更多