使用Mockk验证接收嵌套数据类参数的Lambda时出现AbstractMethodError问题求助
我最近写单元测试时碰到个棘手问题:用Mockk验证接收嵌套数据类参数的Lambda调用时,居然抛出了AbstractMethodError,折腾好一阵都没搞定,特意来求助大家!
先给大家看我的测试代码和相关类:
import io.mockk.verify import org.junit.jupiter.api.Test class DummyTest { @Test fun `dummy test to show issue with mockk`() { val lambdaFunc: (SomeDataClass) -> Unit = { } dummyFunc(lambdaFunc) verify(exactly = 1) { lambdaFunc(any<SomeDataClass>(any())) // 用lambdaFunc(any<SomeDataClass>(any<AnotherDataClass>()))会报参数类型不匹配错误 } } } data class AnotherDataClass(val arg1: String, val arg2: String) sealed class SomeSealedClass { data class SomeDataClass(val anotherDataClass: AnotherDataClass): SomeSealedClass() } fun dummyFunc( onEvent: (SomeDataClass) -> Unit ) { onEvent(SomeDataClass(AnotherDataClass("arg1", "arg2"))) }
运行测试后得到如下错误栈:
Receiver class kotlin.reflect.KClass$Subclass1 does not define or inherit an implementation of the resolved method 'abstract boolean isValue()' of interface kotlin.reflect.KClass. java.lang.AbstractMethodError: Receiver class kotlin.reflect.KClass$Subclass1 does not define or inherit an implementation of the resolved method 'abstract boolean isValue()' of interface kotlin.reflect.KClass. at io.mockk.impl.recording.JvmSignatureValueGenerator.signatureValue(JvmSignatureValueGenerator.kt:19) at io.mockk.impl.recording.states.RecordingState.matcher(RecordingState.kt:46) at io.mockk.impl.recording.CommonCallRecorder.matcher(CommonCallRecorder.kt:52) at io.mockk.MockKMatcherScope.match(API.kt:695) at io.mockk.MockKMatcherScope.any(API.kt:745) at com.sarim.puzzle.data.usecase.DummyTest.dummy_test_to_show_issue_with_mockk$lambda$0(DummyTest.kt:16) at io.mockk.impl.eval.RecordedBlockEvaluator$record$block$1.invoke(RecordedBlockEvaluator.kt:24) at io.mockk.impl.eval.RecordedBlockEvaluator$enhanceWithRethrow$1.invoke(RecordedBlockEvaluator.kt:76) at io.mockk.impl.recording.JvmAutoHinter.autoHint(JvmAutoHinter.kt:23) at io.mockk.impl.eval.RecordedBlockEvaluator.record(RecordedBlockEvaluator.kt:39) at io.mockk.impl.eval.VerifyBlockEvaluator.verify(VerifyBlockEvaluator.kt:30) at io.mockk.MockKDsl.internalVerify(API.kt:120) at io.mockk.MockKKt.verify(MockK.kt:218) at io.mockk.MockKKt.verify$default(MockK.kt:209) at com.sarim.puzzle.data.usecase.DummyTest.dummy test to show issue with mockk(DummyTest.kt:15) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at java.base/java.util.ArrayList.forEach(Unknown Source) at java.base/java.util.ArrayList.forEach(Unknown Source)
我试过把验证语句改成lambdaFunc(any<SomeDataClass>(any<AnotherDataClass>())),但又会报参数类型不匹配的错误。现在我不确定Mockk是不是支持这种嵌套数据类的参数验证,也不知道该怎么修改那行验证代码才能正常工作。
解决思路和方案
首先得明确:你之前的写法any<SomeDataClass>(any())是错误的,any()这个matcher方法并没有接受另一个matcher作为参数的重载,这种错误用法触发了Mockk内部的反射异常,也就是你看到的AbstractMethodError。
针对你的场景,有两种实用的解决方式:
1. 只验证Lambda被调用次数(不关心参数内容)
如果不需要检查参数具体值,只需要确认Lambda被调用了一次,直接简化验证语句即可:
verify(exactly = 1) { lambdaFunc(any()) }
Kotlin会自动推断any()的类型为SomeDataClass,写法简洁且不会出错。
2. 验证嵌套数据类的具体属性值
如果需要确保Lambda被调用时传入的SomeDataClass实例内部的AnotherDataClass属性符合预期,可以用match matcher做自定义检查:
verify(exactly = 1) { lambdaFunc(match { dataClass -> dataClass.anotherDataClass.arg1 == "arg1" && dataClass.anotherDataClass.arg2 == "arg2" }) }
这样就能精准验证嵌套数据类的属性值是否正确,同时避免了之前的错误用法。
另外补充一点:这类反射异常有时候也可能是Mockk版本和Kotlin版本不兼容导致的,建议你确认项目中使用的Mockk版本是否和当前Kotlin版本匹配(比如Mockk 1.13.x对应Kotlin 1.8+,Mockk 1.12.x对应Kotlin 1.7+),如果版本不兼容,升级Mockk到对应版本也能解决问题。
备注:内容来源于stack exchange,提问作者user2287994

