升级jOOQ至3.18后MockK无法模拟其类(3.14版本正常)
jOOQ升级至3.15+后MockK无法模拟TableImpl类的问题
问题背景
我负责的Kotlin项目使用jOOQ与数据库交互,通过jOOQ生成表、字段等Java元模型类,单元测试中用MockK模拟jOOQ的部分类。
简化测试代码如下:
@Test fun `should throw exception for nonexistent fields`() { // given val table = mockk<TableImpl<*>>() every { table.field(any<String>()) } returns null every { table.name } returns "table-name" // when // then }
升级后的报错
将jOOQ从3.14升级到3.18后,MockK无法模拟jOOQ类,报错信息如下:
[io.moc.imp.JvmMockKGateway] (main) Starting JVM MockK implementation. Java version = 11.0.18. [io.moc.pro.jvm.JvmMockKAgentFactory] (main) Byte buddy agent installed [io.moc.pro.jvm.dis.BootJarLoader] (main) Bootstrap class loaded io.mockk.proxy.jvm.dispatcher.JvmMockKDispatcher [io.moc.pro.jvm.dis.BootJarLoader] (main) Bootstrap class loaded io.mockk.proxy.jvm.dispatcher.JvmMockKWeakMap [io.moc.pro.jvm.dis.BootJarLoader] (main) Bootstrap class loaded io.mockk.proxy.jvm.dispatcher.JvmMockKWeakMap$StrongKey [io.moc.pro.jvm.dis.BootJarLoader] (main) Bootstrap class loaded io.mockk.proxy.jvm.dispatcher.JvmMockKWeakMap$WeakKey [io.moc.imp.ins.AbstractMockFactory] (main) Creating mockk for TableImpl name=#1 [io.moc.imp.ins.AbstractMockFactory] (main) Building proxy for TableImpl hashcode=58a4a74d [io.moc.pro.jvm.tra.JvmInlineInstrumentation] (main) Retransforming [Ljava.lang.Class;@6f3f0fae [io.moc.pro.jvm.tra.JvmInlineInstrumentation] (main) Failed to transform classes [ class org.jooq.impl.TableImpl, interface org.jooq.impl.ScopeMappable, interface org.jooq.QueryPartInternal, interface org.jooq.QueryPart, interface java.io.Serializable, interface org.jooq.impl.ScopeNestable, interface org.jooq.impl.SimpleCheckQueryPart, interface org.jooq.impl.QOM$UNotYetImplemented, interface org.jooq.impl.QOM$UEmpty, class org.jooq.impl.AbstractTable, interface org.jooq.Table, interface org.jooq.TableLike, interface org.jooq.Fields, interface org.jooq.RecordQualifier, interface org.jooq.Qualified, interface org.jooq.Named, interface org.jooq.GroupField, interface org.jooq.SelectField, interface org.jooq.SelectFieldOrAsterisk, interface org.jooq.Typed, interface org.jooq.impl.FieldsTrait, interface org.jooq.impl.QOM$Aliasable, class org.jooq.impl.AbstractNamed, class org.jooq.impl.AbstractQueryPart, class java.lang.Object ]: java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method) at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:167) at io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation.retransform(JvmInlineInstrumentation.kt:28) at io.mockk.proxy.common.transformation.RetransformInlineInstrumentation$execute$1.invoke(RetransformInlineInstrumentation.kt:19) at io.mockk.proxy.common.transformation.RetransformInlineInstrumentation$execute$1.invoke(RetransformInlineInstrumentation.kt:16) at io.mockk.proxy.common.transformation.ClassTransformationSpecMap.applyTransformation(ClassTransformationSpecMap.kt:41) at io.mockk.proxy.common.transformation.RetransformInlineInstrumentation.execute(RetransformInlineInstrumentation.kt:16) at io.mockk.proxy.jvm.ProxyMaker.inline(ProxyMaker.kt:88) at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:30) at io.mockk.impl.instantiation.JvmMockFactory.newProxy(JvmMockFactory.kt:34) at io.mockk.impl.instantiation.AbstractMockFactory.newProxy$default(AbstractMockFactory.kt:24) at io.mockk.impl.instantiation.AbstractMockFactory.mockk(AbstractMockFactory.kt:59) at my-test-here
jOOQ的代码变更导致MockK无法修改类以生成模拟对象/代理,目前尚未明确MockK具体要执行的修改操作。MockK的issue追踪器中有类似问题,但原因仍不明确。我对比了jOOQ 3.14到3.18版本间TableImpl的变更,未发现明显异常。
问题定位
搭建重现项目后发现,问题从jOOQ 3.14.16升级到3.15版本时开始出现。
MockK的跟踪日志给出了关键线索:
jOOQ 3.14.16版本日志:
... [io.mockk.impl.instantiation.AbstractMockFactory] (main) Creating mockk for TableImpl name=#1 [io.mockk.impl.instantiation.AbstractMockFactory] (main) Building proxy for TableImpl hashcode=290b1b2e [io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation] (main) Retransforming [Ljava.lang.Class;@7d755813 [io.mockk.proxy.common.ProxyMaker] (main) Taking instance of class org.jooq.impl.TableImpl itself because it is not abstract and no additional interfaces specified. [io.mockk.proxy.common.ProxyMaker] (main) Instantiating proxy for class org.jooq.impl.TableImpl via instantiator ...
jOOQ 3.15.0版本日志:
[io.mockk.impl.instantiation.AbstractMockFactory] (main) Creating mockk for TableImpl name=#1 [io.mockk.impl.instantiation.AbstractMockFactory] (main) Building proxy for TableImpl hashcode=6fff253c [io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation] (main) Retransforming [Ljava.lang.Class;@72fe8a4f [io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation] (main) Failed to transform classes
在3.14.16版本中,MockK不需要为TableImpl构建代理,因为它是非抽象类且未指定额外接口,直接通过实例化器创建实例即可。
目前该问题已提交至MockK的issue。
内容的提问来源于stack exchange,提问作者Marcel Stör
相关产品推荐
相关产品推荐

