调用私有挂起函数时参数不匹配,求助排查缺失的第三个参数
问题:调用私有挂起函数时触发参数不匹配异常
我使用扩展函数调用ViewModel中的私有挂起函数setUpArea(areaId: Long),调用代码为viewModel.callPrivateFunc("setUpArea", 2L),运行测试时抛出IllegalArgumentException,提示“Callable expects 3 arguments, but 2 were provided”,无法确定缺失的第三个参数。
相关代码
测试代码
@Before fun setUp() { savedStateHandle = SavedStateHandle() savedStateHandle["areaId"] = 1L saveImageUseCase = Mockito.mock(SaveImageUseCase::class.java) repo = FakeRepository() viewModel = AreaEditViewModel(repo, savedStateHandle, saveImageUseCase) } @Test fun setUpArea() = runTest { viewModel.callPrivateFunc("setUpArea", 2L) }
ViewModel代码
private suspend fun setUpArea(areaId: Long) { repository.getAreaById(areaId).first() { savedStateHandle["area"] = it true } }
原因分析
Kotlin的挂起函数会被编译器自动注入一个Continuation类型的参数,这是协程实现挂起/恢复逻辑的底层机制。因此你定义的setUpArea(areaId: Long)在编译后,实际方法签名会变成setUpArea(Long, Continuation<? super Unit>)。
而你使用的扩展函数在反射调用时,只传入了areaId参数,没有提供这个隐式的Continuation参数,加上成员方法反射调用时需要传入实例本身作为第一个参数,就导致了“期望3个参数(实例、areaId、Continuation)但只传入了2个(实例、areaId)”的异常。
解决方案
要正确调用私有挂起函数,需要修改扩展函数以支持协程,这里提供适配挂起函数的扩展函数实现:
import kotlin.coroutines.Continuation import kotlin.coroutines.EmptyCoroutineContext suspend fun <T : Any> T.callPrivateSuspendFunc(name: String, vararg args: Any?): Any? { val continuation = Continuation(EmptyCoroutineContext) { result -> result.getOrThrow() } val methodParams = args.map { it?.javaClass } + Continuation::class.java val method = javaClass.getDeclaredMethod(name, *methodParams.toTypedArray()) method.isAccessible = true return method.invoke(this, *args, continuation) }
然后在测试中这样调用:
@Test fun setUpArea() = runTest { viewModel.callPrivateSuspendFunc("setUpArea", 2L) }
内容的提问来源于stack exchange,提问作者RCH
相关产品推荐
相关产品推荐

