mockito Kotlin中的模拟扩展函数

tgabmvqs  于 9个月前  发布在  Kotlin
关注(0)|答案(5)|浏览(87)

如何在测试中使用Mockito或PowerMock模拟Kotlin扩展函数?既然它们是静态解析的,那么它们应该被测试为静态方法调用还是非静态方法调用?

shyt4zoc

shyt4zoc1#

我想MockK能帮你
它也支持mocking * 扩展函数 *。
你可以使用它来模拟对象范围的扩展:

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)。
在jvm环境中,你可以用函数引用替换类名:

mockkStatic(Obj::extensionFunc)

注意,这将模拟整个pkg.FileKt类,而不仅仅是extensionFunc。
此语法也适用于扩展属性:

val Obj.squareValue get() = value * value

mockkStatic(Obj::squareValue)

更多信息可以在这里找到:网站和github

busg9geu

busg9geu2#

示例扩展函数可以在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)
}
u3r8eeie

u3r8eeie3#

首先,Mockito对Kotlin特定的语言结构一无所知。最后,Mockito将查看**字节码。Mockito只能理解它在那里找到的东西,以及看起来像Java语言构造的东西。
含义:为了更加确定,您可能需要使用javap来反汇编编译后的类文件,以确定您想要模拟的方法的确切名称/签名。
很明显:当该方法是 static 时,您必须使用PowerMock或JMockit;如果没有,你应该更喜欢和莫奇托在一起。
从Java的Angular 来看,您可以简单地避免模拟静态的东西;但是,当然,事情变得非常有趣,现在不同的语言与不同的想法/概念走到一起。

f0brbegy

f0brbegy4#

我使用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
cmssoen2

cmssoen25#

使用Mockk库,
ContextExt.kt文件中给定一个顶级(意味着没有在类中声明)扩展方法,例如:

Context.doSomething(param1: Int, param2: String = "default") : Int {
   // Does something that wouldn't work in your test environment
}

为了模仿它,我们可以做以下事情:

MyTestClass {
   companion object {
       private const val MOCKED_VALUE = 10
   }
   ...

   @Before
   fun before() {
      mockkStatic("com.my.package.ContextExtKt")
      every { any<Context>().doSomething(any(), any()) } returns MOCKED_VALUE
   }
}

有几件事要小心:
1.你提供给mockkStatic的参数是在你的文件的第一行声明的包名+文件名+“Kt”。例如,对于com.my.package包中的文件ContextExt.kt,您需要:mockkStatic("com.my.package.ContextExtKt")
1.为您试图模拟的扩展方法提供所有参数,即使它们具有默认值。如果需要,可以使用特定值,否则使用any()

相关问题