模拟私人财产

Jam*_*ney 5 mockk

可以说我们有一个这样的类:

class Whatever {
    private var something = false

    fun aMethod(): Int {
        return if( something ) {
            1
        } else {
            0
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

根据文档,看来我应该能够执行以下操作:

val classUnderTest = spyk(Whatever())

every { classUnderTest getProperty "something" } returns true

assertThat(classUnderTest.aMethod()).isEqualTo(1)
Run Code Online (Sandbox Code Playgroud)

但是我得到了错误: io.mockk.MockKException: Missing calls inside every { ... } block

我正在使用Mockk 1.8.5,Kotlin 1.2.51

Ign*_*spo 9

您可以使用这个小扩展

fun Any.mockPrivateFields(vararg mocks: Any): Any {
    mocks.forEach { mock ->
        javaClass.declaredFields
                .filter { it.modifiers.and(Modifier.PRIVATE) > 0 || it.modifiers.and(Modifier.PROTECTED) > 0 }
                .firstOrNull { it.type == mock.javaClass}
                ?.also { it.isAccessible = true }
                ?.set(this, mock)
    }
    return this
}
Run Code Online (Sandbox Code Playgroud)

它设置作为参数传递的相同类型的第一个字段的值,并且可以使用多个参数,例如:

myObject.mockPrivateFields(1, "hi!")
Run Code Online (Sandbox Code Playgroud)

它将模拟找到的第一个 Int 字段和找到的第一个 String 字段。

这仅适用于私有/受保护的字段。

您可以修改它以支持同一类型的多个字段。我没有尝试使用泛型,但我想支持它并不困难。

  • 这是一种非常有趣的方法。我想知道为什么它不是带有像“@Inject”这样的注释的 MockK 库的一部分 (4认同)

Vov*_*huk 5

尝试使用答案而不是返回,如下所示:

val mock = spyk(MockCls(), recordPrivateCalls = true)

every { mock.property } answers { fieldValue }
every { mock getProperty "property" } propertyType Int::class answers { fieldValue + 6 }
every { mock setProperty "property" value any<Int>() } propertyType Int::class answers  { fieldValue += value }
every { mock.property = any() } propertyType Int::class answers {
  fieldValue = value + 1
} andThen {
  fieldValue = value - 1
}
Run Code Online (Sandbox Code Playgroud)

  • 我想知道您是否可以添加一些解释而不仅仅是原始代码?@沃娃 (6认同)