0

我很难尝试使用反射在 Kotlin 中获取私有方法,以便将其作为参数传递给更高阶函数,这是我得到的以及我需要做的:

获取私有方法的函数,可能是我应该更改或修复的:

inline fun <reified T> T.getPrivateFunc(name: String): KFunction<*> {
    return T::class.declaredMemberFunctions.first { 
        it.name == name 
    }.apply { 
        isAccessible = true 
    }
}

这是我拥有的高阶函数:

class MyService {

    fun myHigherOrderFunction(action: () -> Unit) { /*...*/ }
}

这些是我需要以某种方式获得的类和私有方法:

class SystemUnderTest {

    fun privateFunc() { /*...*/ }
}

最后是一个单元测试,我试图确保将正确的方法传递给高阶函数,为了简化,我省略了细节:

// ...
val serviceMock = MyService()
val sut = SystemUnderTest()
// Here is what I'm trying to accomplish
val privateMethod = sut.getPrivateMethod("privateFunc")
service.myHighOrderFunction(privateMethod) 
// In the above line I get a compilation error: required () - Unit, found KFunction<*>
service.myHigherOrderFunction(privateMethod as () -> Unit) 
// In the above line I get the following runtime error:
// ClassCastException: kotlin.reflect.jvm.internal.KFunctionImpl cannot be cast to kotlin.jvm.functions.Function1

我知道可以使用privateFuncas进行测试,也可以使用 进行public注释@VisibleForTesting,但我想要的是尽可能避免损害设计。

有任何想法吗?提前致谢!

4

1 回答 1

0

我认为 KFunction 和 KCallable 没有任何绑定接收器的概念,因此它们不可调用(没有operator fun invoke),因此不符合函数的条件。所以我认为你必须将 KFunction 对象包装在一个函数中,以便能够将它传递给你的高阶函数。要调用 KFunction,请将接收器类的实例作为第一个参数传递。

val serviceMock = MyService()
val sut = SystemUnderTest()
val privateMethod = sut.getPrivateMethod("privateFunc")
service.myHighOrderFunction { privateMethod.call(sut) }

编辑:要内部化包装函数的创建,您可以这样做:

inline fun <reified T> T.getZeroArgPrivateMethod(name: String): () -> Unit = {
    T::class.declaredMemberFunctions.first {
        it.name == name
    }.apply {
        isAccessible = true
    }.call(this)
}

//...

val serviceMock = MyService()
val sut = SystemUnderTest()
val privateMethod = sut.getZeroArgPrivateMethod("privateFunc")
service.myHighOrderFunction(privateMethod)
于 2021-05-21T15:50:54.837 回答