运行Cucumber测试时出现ExceptionInInitializerError问题求助
运行Cucumber测试时初始化错误的分析与解决
问题描述
运行Cucumber测试时触发初始化错误,使用的TestRunner代码如下:
package myTestRunner; import org.junit.runner.RunWith; import cucumber.api.CucumberOptions; import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class) @CucumberOptions( features="features", glue="stepDefinitions" ) public class TestRunner { }
执行后抛出如下异常:
java.lang.ExceptionInInitializerError at cucumber.deps.com.thoughtworks.xstream.XStream.setupConverters(XStream.java:820) at cucumber.deps.com.thoughtworks.xstream.XStream.<init>(XStream.java:574) at cucumber.deps.com.thoughtworks.xstream.XStream.<init>(XStream.java:530) at cucumber.runtime.xstream.LocalizedXStreams$LocalizedXStream.<init>(LocalizedXStreams.java:50) at cucumber.runtime.xstream.LocalizedXStreams.newXStream(LocalizedXStreams.java:37) at cucumber.runtime.xstream.LocalizedXStreams.get(LocalizedXStreams.java:29) at cucumber.runtime.StepDefinitionMatch.runStep(StepDefinitionMatch.java:37) at cucumber.runtime.Runtime.runStep(Runtime.java:300) at cucumber.runtime.model.StepContainer.runStep(StepContainer.java:44) at cucumber.runtime.model.StepContainer.runSteps(StepContainer.java:39) at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:44) at cucumber.runtime.junit.ExecutionUnitRunner.run(ExecutionUnitRunner.java:102) at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:63) at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:18) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at cucumber.runtime.junit.FeatureRunner.run(FeatureRunner.java:70) at cucumber.api.junit.Cucumber.runChild(Cucumber.java:95) at cucumber.api.junit.Cucumber.runChild(Cucumber.java:38) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at cucumber.api.junit.Cucumber.run(Cucumber.java:100) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210) at ✽.Given Open the browser(MyAccount_Login.feature:6) Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Comparator java.util.TreeMap.comparator accessible: module java.base does not "opens java.util" to unnamed module @606d8acf at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:180) at java.base/java.lang.reflect.Field.setAccessible(Field.java:174) at cucumber.deps.com.thoughtworks.xstream.core.util.Fields.locate(Fields.java:39) at cucumber.deps.com.thoughtworks.xstream.converters.collections.TreeMapConverter.<clinit>(TreeMapConverter.java:50) ... 35 more
原因分析
这个错误的核心是Java 9+的模块化系统与旧版本Cucumber依赖的XStream版本不兼容:
- 旧版本Cucumber内嵌的XStream库会通过反射访问Java核心模块(
java.base)中java.util.TreeMap的私有字段comparator; - Java 9及以上引入的模块系统默认禁止非模块代码(无名模块)访问核心模块的内部私有成员,因此抛出
InaccessibleObjectException,进而引发初始化异常ExceptionInInitializerError。
解决办法
1. 升级Cucumber版本(推荐方案)
升级到支持Java 9+的Cucumber版本(4.8.0及以上,建议用最新稳定版),这些版本已修复XStream的兼容性问题,部分新版本甚至替换了XStream为其他序列化库。
如果使用Maven,替换原有依赖为:
<dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-java</artifactId> <version>7.14.0</version> <scope>test</scope> </dependency> <dependency> <groupId>io.cucumber</groupId> <artifactId>cucumber-junit</artifactId> <version>7.14.0</version> <scope>test</scope> </dependency>
注意:旧版的cucumber.api包已废弃,需改用io.cucumber的groupId。
2. 添加JVM启动参数(临时 workaround)
如果暂时无法升级Cucumber,可通过JVM参数允许无名模块访问java.base的java.util包:
--add-opens java.base/java.util=ALL-UNNAMED
在Eclipse中,可在Run Configuration的VM arguments中添加该参数。
3. 降级Java版本
若项目允许,将Java版本降级到Java 8,Java 8没有模块系统,不会存在此类权限限制问题。
内容的提问来源于stack exchange,提问作者Madhusudhan Vm
相关产品推荐
相关产品推荐

