在使用Robolectric的项目中集成PowerMock遇到异常问题
解决PowerMock+Robolectric测试中的DeepCloner实例化异常
我正在为依赖Android特定组件的类编写测试,使用版本:Robolectric 4.10.3、PowerMock 2.0.9。运行测试时抛出以下异常:
Failed to instantiate DeepCloner. The DeepCloner implementation must have a one-arg constructor taking a Classloader as parameter. java.lang.RuntimeException: Failed to instantiate DeepCloner. The DeepCloner implementation must have a one-arg constructor taking a Classloader as parameter. at org.powermock.classloading.AbstractClassloaderExecutor.doCreateDeepCloner(AbstractClassloaderExecutor.java:108) at org.powermock.classloading.AbstractClassloaderExecutor.createDeepCloner(AbstractClassloaderExecutor.java:97) at org.powermock.classloading.AbstractClassloaderExecutor.executeWithClassLoader(AbstractClassloaderExecutor.java:52) at org.powermock.classloading.SingleClassloaderExecutor.execute(SingleClassloaderExecutor.java:33) at org.powermock.classloading.AbstractClassloaderExecutor.execute(AbstractClassloaderExecutor.java:40) at org.powermock.modules.junit4.rule.PowerMockStatement.evaluate(PowerMockRule.java:75) at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306) at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:589) at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$2(SandboxTestRunner.java:290) at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:99) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:840) Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) at org.powermock.classloading.AbstractClassloaderExecutor.doCreateDeepCloner(AbstractClassloaderExecutor.java:106) ... 13 more Caused by: java.lang.ExceptionInInitializerError at com.thoughtworks.xstream.converters.extended.FontConverter.<init>(FontConverter.java:56) at com.thoughtworks.xstream.XStream.setupConverters(XStream.java:1008) at com.thoughtworks.xstream.XStream.<init>(XStream.java:592) at com.thoughtworks.xstream.XStream.<init>(XStream.java:514) at com.thoughtworks.xstream.XStream.<init>(XStream.java:483) at com.thoughtworks.xstream.XStream.<init>(XStream.java:429) at com.thoughtworks.xstream.XStream.<init>(XStream.java:368) at org.powermock.classloading.DeepCloner.<init>(DeepCloner.java:35) ... 19 more Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected java.lang.String java.text.AttributedCharacterIterator$Attribute.getName() accessible: module java.base does not "opens java.text" to unnamed module @fdc3812 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.Method.checkCanSetAccessible(Method.java:199) at java.base/java.lang.reflect.Method.setAccessible(Method.java:193) at com.thoughtworks.xstream.converters.reflection.AbstractAttributedCharacterIteratorAttributeConverter.<clinit>(AbstractAttributedCharacterIteratorAttributeConverter.java:45) ... 27 more
已尝试在build.gradle的testOptions中添加以下JVM参数,但问题未解决:
all { jvmArgs '--add-opens=java.base/java.lang.reflect=ALL-UNNAMED', '--add-opens=java.base/java.lang=ALL-UNNAMED', '--add-opens=java.base/java.util=ALL-UNNAMED' }
解决方案
从异常根因来看,是XStream尝试访问java.text.AttributedCharacterIterator$Attribute的getName()方法时,受Java模块系统限制无法获取访问权限。需要补充对应的模块开放参数:
- 补充JVM参数:修改build.gradle的testOptions配置,添加
--add-opens=java.base/java.text=ALL-UNNAMED参数,完整配置如下:
testOptions { unitTests { all { jvmArgs '--add-opens=java.base/java.lang.reflect=ALL-UNNAMED', '--add-opens=java.base/java.lang=ALL-UNNAMED', '--add-opens=java.base/java.util=ALL-UNNAMED', '--add-opens=java.base/java.text=ALL-UNNAMED' } } }
升级PowerMock版本:若补充参数后仍有问题,可尝试升级PowerMock至2.0.10或更高版本,新版本对Java 9+模块系统的兼容性更好,可能已修复此类反射权限相关问题。
检查JDK版本兼容性:PowerMock 2.0.x系列对JDK 11及以上版本需要正确配置模块开放参数,确保没有遗漏必要的包路径。
内容的提问来源于stack exchange,提问作者SyntaxSage
相关产品推荐
相关产品推荐

