【问题标题】:Mock a private property模拟私有财产
【发布时间】:2023-03-17 17:57:01
【问题描述】:

假设我们有一个这样的类:

class Whatever {
    private var something = false

    fun aMethod(): Int {
        return if( something ) {
            1
        } else {
            0
        }
    }
}

根据documentation,看来我应该能够做到以下几点:

val classUnderTest = spyk(Whatever())

every { classUnderTest getProperty "something" } returns true

assertThat(classUnderTest.aMethod()).isEqualTo(1)

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

我正在使用 mockk 1.8.5、kotlin 1.2.51

【问题讨论】:

  • 目前,AFAIK,私人properties mocking are not yet supported。检查链接的问题以了解此行为的发展
  • 为什么不使用getter?并嘲笑它。
  • @RafaelRuizMuñoz 不想公开或创建仅用于测试的方法
  • 你总是可以使用 Super Reflect github.com/dpreussler/SuperReflect 但对我来说,我不知道如何,当testCoverage false 时它不起作用
  • @RafaelRuizMuñoz 我试过了,但它不起作用。你真的尝试过吗?对你有用吗?

标签: kotlin mockk


【解决方案1】:

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

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
}

【讨论】:

  • 我想知道您是否可以添加一些解释而不仅仅是原始代码? @Vova
【解决方案2】:

你可以使用这个小扩展

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
}

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

myObject.mockPrivateFields(1, "hi!")

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

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

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

【讨论】:

  • 这是一种非常有趣的方式。我想知道为什么它不是 MockK 库的一部分,带有 @Inject 之类的注释
【解决方案3】:

这可能是因为 there is no getter/setter created 被 kotlin 编译器为你的 something 属性。

如果你把它修改成下面的样子呢?

class Whatever {
    private val something
        get() = false

    fun aMethod(): Int {
        return if( something ) {
            1
        } else {
            0
        }
    }
}

【讨论】:

    猜你喜欢
    • 2020-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多