JMockit with JDK 11

Posted by Mark on July 15, 2020

简述

项目从 JDK 8 升级为 JDK 11的过程中,

由于项目中使用了 JMockit, 导致项目单元测试执行一直失败,

本文记录解决单元测试执行失败以及JMockit 升级的过程.

JDK 8升级为JDK 11, JMockit 1.37

项目使用 JDK 8 时, JMockit 使用版本为 1.37,

在写单元测试时, 一直使用 @Tested, @Injectable 来进行测试类初始化和注入测试类依赖,

在升级为JDK 11之后, 运行单元测试, IDEA 提示以下错误:

java.lang.IllegalStateException: Running on JDK 9 requires -javaagent:<proper path>/jmockit-1.n.jar or -Djdk.attach.allowAttachSelf

查看 maven.surefire.plugin 文档得知, 2.1 版本之后 插件执行时允许用户添加命令至JVM选项,

根据提示在 properties.argLine 增加 -Djdk.attach.allowAttachSelf

1
2
3
4
5
6
<properties>
    // ...other properities
    <argLine>
        -Djdk.attach.allowAttachSelf
    </argLine>
</properties>

再次运行单元测试, 上面错误没有了, IDEA 又提示以下错误

1
2
3
java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the class NestHost or NestMembers attribute

at java.instrument/sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)

依据关键信息: attempted to change the class NestHost or NestMembers attribute,

得知此问题是由于 JDK 11 发布后的增强型提案 JEP181: 嵌套控制访问 引发的.

查看 jmockit github issue 关于 Java 11 的 issue 记录, 看到 issue/534:JMockit on Java 11 相关讨论

其中一条关键的信息: rliesenfeld closed this in c5fffc1 on 23 Sep 2018, 得知 JMockit Member 已经修复了此问题.

通过 JMockit release notes#1.43 也可以印证

  • Deprecated the withArgThat(Matcher) method (available in the Expectations and Verifications classes), in favor of argument capturing (the withCapture(…) methods) and the with(Delegate) method.
  • Issues closed: #534.

JDK 11, JMockit 1.49

我们将 JMockit 版本 升级为当前最新版本 1.49 后,

发现 JMockit.class 被移除, 之前在测试类增加的注解 @RunWith(JMockit.class) 需要移除.

清理干净后 重新执行单元测试, 发现 @Tested 修饰的类实例总是为 null,

查看 JMockit release notes#1.42,

  • JMockit now requires the use of the "-javaagent" JVM initialization parameter. See Running tests with JMockit.
  • Dropped support for mock parameters in TestNG methods.
  • Issues closed: #515, #542.

得知 1.42 之后 使用任何 JMockit API, 都需要使用 -javaagent:<proper path>/jmockit.1.x.jar 进行测试JVM初始化,

这里需要将之前增加的 -Djdk.attach.allowAttachSelf 替换为 -javaagent, 至此问题解决.

1
2
3
4
5
6
<properties>
    // ...other properities
    <argLine>
        -javaagent:"${settings.localRepository}"/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar
    </argLine>
</properties>

Maven 相关修改请参照: 4.1 Running tests from Maven, 这里不再拷贝.

总结

排查 JMockit的问题, JMockit release notes 一定要细看, 重点信息都在上面了.

如有错误, 欢迎评论指正或者联系我, 我会及时修正。