【问题标题】:java.lang.ClassFormatError: Invalid method Code length while using PowerMockjava.lang.ClassFormatError:使用 PowerMock 时方法代码长度无效
【发布时间】:2016-08-15 00:44:25
【问题描述】:

我正在使用以下库在 jdk7 中使用 PowerMock 运行 JUnit 案例:

cglib-nodep-2.2.2.jar
javassist-3.19.0-GA.jar
junit-4.12.jar
mockito-all-1.10.19.jar
objenesis-2.1.jar
powermock-mockito-1.6.2-full.jar

下面是我使用 PowerMock 的单元测试中的代码 sn-p

@RunWith(PowerMockRunner.class)
@PrepareForTest(ValidateBindingImpl.class)
public class ValidateBindingImplTest{

//more code follows
}

在执行此测试用例时,我收到以下错误:

java.lang.ClassFormatError: Invalid method Code length 119842 in class file com/v1/ValidateBindingImpl
    at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.lang.ClassLoader.defineClass(ClassLoader.java:465)
at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:269)
at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:180)
at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:68)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:249)
at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:95)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:107)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:31)
at sun.reflect.annotation.AnnotationParser.parseSig(AnnotationParser.java:370)
at sun.reflect.annotation.AnnotationParser.parseClassValue(AnnotationParser.java:351)
at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:653)
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:460)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:286)
at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:222)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:69)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:52)
at java.lang.Class.initAnnotationsIfNecessary(Class.java:3079)
at java.lang.Class.getAnnotation(Class.java:3038)
at org.junit.internal.MethodSorter.getDeclaredMethods(MethodSorter.java:52)
at org.junit.internal.runners.TestClass.getAnnotatedMethods(TestClass.java:45)
at org.junit.internal.runners.MethodValidator.validateTestMethods(MethodValidator.java:71)
at org.junit.internal.runners.MethodValidator.validateStaticMethods(MethodValidator.java:44)
at org.junit.internal.runners.MethodValidator.validateMethodsForDefaultRunner(MethodValidator.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.validate(PowerMockJUnit44RunnerDelegateImpl.java:108)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.<init>(PowerMockJUnit44RunnerDelegateImpl.java:70)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl.<init>(PowerMockJUnit47RunnerDelegateImpl.java:42)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl.<init>(PowerMockJUnit49RunnerDelegateImpl.java:25)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:156)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:40)
at org.powermock.tests.utils.impl.AbstractTestSuiteChunkerImpl.createTestDelegators(AbstractTestSuiteChunkerImpl.java:244)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.<init>(JUnit4TestSuiteChunkerImpl.java:61)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.<init>(AbstractCommonPowerMockRunner.java:32)
at org.powermock.modules.junit4.PowerMockRunner.<init>(PowerMockRunner.java:34)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:29)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:21)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.<init>(JUnit4TestReference.java:33)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.<init>(JUnit4TestClassReference.java:25)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:48)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:444)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

发现讨论了herehere 的类似帖子,基于该帖子我尝试在VM 参数中添加-XX:-UseSplitVerifier,但没有成功。

此外,我了解该错误似乎是由于我的类文件中的冗长方法而发生的,但作为我的组织代码,我将无法按照某些在线帖子中的建议修改/拆分该方法。

【问题讨论】:

    标签: junit java-7 powermock


    【解决方案1】:

    要使用 JVM 选项“-noverify”:https://bugs.eclipse.org/bugs/show_bug.cgi?id=435446

    【讨论】:

    • 就我而言,这个问题与 javassist 版本有关,我在线程“错误模拟类包含对 SQLiteOpenHelper 的引用”中报告:stackoverflow.com/questions/47768644/…
    • 这只会让 JVM 崩溃而不是抛出异常。
    【解决方案2】:

    如前所述,这不仅可以通过尝试检测大型方法来实现,还可以通过尝试用大量方法检测类来实现。

    我在around +/- 1500 methods 遇到了休息时间。这取决于类中的方法签名。

    尽量减少类中方法的数量。

    【讨论】:

    • 不是方法个数,但是每个方法不能大于64KB。一个是 119842 Bytes 根据错误消息。
    【解决方案3】:

    你可能不会喜欢我的回答,但唯一合理的回答是:停止使用 PowerMock。

    如果您的生产代码需要 PowerMock 才能编写单元测试;然后认真:更改您的生产代码。如果您需要 PowerMock,那么您的“待测代码”很可能是:不好。

    PowerMock(以及所有其他依赖字节码操作的模拟框架)通常带来的麻烦多于好处。它们会引起您现在遇到的问题;它们极大地限制了您使用不同 JVM 或运行覆盖工具的能力。

    这来自一个花费无数时间修复基于“PowerMock”的单元测试的人;在过去的几个月里,谁只依靠 EasyMock 编写了数百个单元测试;并且没有一次需要求助于 PowerMock。

    【讨论】:

    • @GhostCat 是否可以使用 EasyMock 测试私有方法、静态内容?
    • @john A) 你不 test 私有方法 - 它们包含实现细节,你测试 public 方法 B) 当然你可以 test 静态方法......但我猜你的意思是说“我可以使用 EasyMock mock 私有/静态方法吗?”答案是:不,你不能
    • @GhostCat 很抱歉不清楚。是的,特别是,你能嘲笑他们吗?如果您有一些特定算法在同一个类中多次使用,那么将其作为私有方法并在多个公共方法中使用是否有意义?而且您的公共方法可能不仅仅是调用该私有方法,并且您编码的算法包含一些您想要测试以验证它产生正确结果的逻辑,您会怎么做?
    • @john 如果您的算法是您代码的核心部分……那么它可能值得拥有自己的。换句话说:阅读罗伯特马丁的干净代码书。您的问题表明您缺乏如何合理构建源代码的知识;-)
    • @GhostCat 我完全同意。我会的)
    【解决方案4】:

    您遇到了以下issue:JVM 对方法大小的字节数有限制,但在字节码转换过程中需要使模拟静态成为可能,方法的最终大小可能会超过此限制。在这种情况下,您会看到此错误

    java.lang.ClassFormatError: Invalid method Code length 119842 in class file
    

    在下一个版本中将包含修复,它通过替换巨大的方法来解决这个问题,该方法默认抛出异常,但你仍然可以抑制这样的方法。

    但是,它仍然是您无法修改的类的唯一解决方法。解决问题的正确方法是重构代码以使方法更小。有很多重构技术可以实现这个目标。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-09
      • 1970-01-01
      • 2014-11-26
      • 2019-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-08
      相关资源
      最近更新 更多