kotlin中的模拟扩展功能



如何在测试中使用Mockito或PowerMock模拟Kotlin扩展功能?既然它们在静态上解决了,应该将它们作为静态方法调用或非静态测试?

我认为 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(。

可以在此处找到更多信息:网站和github

实例扩展功能可以在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)
}

首先,Mockito知道 nothing kotlin特定语言构造。最后,Mockito将在字节代码中以外观。Mockito只能理解它在那里发现的东西以及看起来像Java语言构造的东西。

含义:要肯定,您可能需要使用Javap来重新组装编译的ClassFiles来确定要模拟的方法的确切名称/签名。

显然:当该方法为 static 时,您必须使用用户powermock或jmockit;如果没有,您应该更喜欢使用Mockito。

从Java的角度来看,您只需避免嘲笑静态东西即可;但是,当然,现在有不同想法/概念的不同语言融合在一起。

i使用 MOCKK library。

对于扩展文件写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

使用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. Argyou提供给Mockkstatic的是文件的包装名称,如文件的第一行 文件名 'kt'。例如,对于包装 com.my.package中的文件 ContextExt.kt,您需要: mockkStatic("com.my.package.ContextExtKt")
  2. 即使它们具有默认值,也将所有ARG提供给您要模拟的扩展方法。如果需要,请使用特定值,否则请使用any()

最新更新