【问题标题】:PowerMock & JavaAssist "Failed to transform class"PowerMock & JavaAssist“转换类失败”
【发布时间】:2016-03-31 06:31:14
【问题描述】:

在使用 PowerMock 进行单元测试时,我遇到了一些特定类及其转换的问题。

我已经查看了许多 SO 响应,并尝试了 PowerMock、JUnit、JavaAssist(覆盖依赖项)的许多组合,但找不到适用于此类的组合。

(PowerMock、Junit 和 Javaassist 的某些组合没有这个问题,但是无效的堆栈帧之一......所以也卡在那里 - 但我必须在单独的 SO 问题中解决这个问题)。

如果我在 @PrepareForTest() 列表中包含类 ToplevelPanel,那么它会失败。其他 JavaFX 类(如 Pane.class)不会出现问题。

ToplevelPanel 并没有什么特别奇怪的地方:

public class ToplevelPane extends Region implements BlockContainer, Bundleable {

Bundleable 没有@Serializable 注释或任何特殊的东西。

当我测试 ToplevelPanel 并希望它在 @PrepareForTest 中能够通​​过 whenNew() 捕获 new() 以及当我测试其他类并想要模拟它时,这会失败。

如果有人可以分享一个 pom.xml 或版本组合,让我可以@PrepareForTest 这样一个类,包括捕获 whenNew(),那将不胜感激。

在这篇文章的底部,您可以找到失败的堆栈跟踪。

pom.xml

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <junit.version>4.11</junit.version>
    <powermock.version>1.5.1</powermock.version>
  </properties>

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>${junit.version}</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>${powermock.version}</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito</artifactId>
  <version>${powermock.version}</version>
  <scope>test</scope>
</dependency>

单元测试代码

import nl.utwente.viskell.haskell.env.Environment;
import nl.utwente.viskell.haskell.type.Type;
import nl.utwente.viskell.ui.ToplevelPane;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Type.class, ToplevelPane.class, Environment.class})
public class ValueBlockTest {
    private ToplevelPane mockToplevelPane;

    @Before
    public void Setup() {
        mockToplevelPane = mock(ToplevelPane.class, RETURNS_DEEP_STUBS);
        Environment mockEnv = mock(Environment.class);
        Type mockType = mock(Type.class);
        when(mockEnv.buildType(any())).thenReturn(mockType);
        when(mockToplevelPane.getEnvInstance()).thenReturn(mockEnv);
    }

    @Test
    public void outputTest() throws Exception {
        ConstantBlock block = new ConstantBlock(mockToplevelPane, Type.con("Float"), "0.0", true);
        block.setValue("6");
        assertEquals(block.getValue(), "6");
    }
}

失败堆栈跟踪

java.lang.IllegalStateException:无法转换具有名称的类 nl.utwente.viskell.ui.ToplevelPane。原因: javassist.bytecode.InterfaceMethodrefInfo 不能强制转换为 javassist.bytecode.MethodrefInfo 在 org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:219) 在 org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:147) 在 org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:67) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 java.lang.Class.forName0(本机方法)在 java.lang.Class.forName(Class.java:348) 在 sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114) 在 sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125) 在 sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49) 在 sun.reflect.annotation.AnnotationParser.parseSig(AnnotationParser.java:439) 在 sun.reflect.annotation.AnnotationParser.parseClassValue(AnnotationParser.java:420) 在 sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:724) 在 sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:531) 在 sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355) 在 sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286) 在 sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120) 在 sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72) 在 java.lang.Class.createAnnotationData(Class.java:3521) 在 java.lang.Class.annotationData(Class.java:3510) 在 java.lang.Class.getAnnotation(Class.java:3415) 在 org.junit.internal.MethodSorter.getDeclaredMethods(MethodSorter.java:52) 在 org.junit.internal.runners.TestClass.getAnnotatedMethods(TestClass.java:45) 在 org.junit.internal.runners.MethodValidator.validateTestMethods(MethodValidator.java:71) 在 org.junit.internal.runners.MethodValidator.validateStaticMethods(MethodValidator.java:44) 在 org.junit.internal.runners.MethodValidator.validateMethodsForDefaultRunner(MethodValidator.java:50) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.validate(PowerMockJUnit44RunnerDelegateImpl.java:108) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.(PowerMockJUnit44RunnerDelegateImpl.java:70) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl.(PowerMockJUnit47RunnerDelegateImpl.java:42) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl.(PowerMockJUnit49RunnerDelegateImpl.java:25) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native 方法)在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:422) 在 org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:143) 在 org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:39) 在 org.powermock.tests.utils.impl.AbstractTestSuiteChunkerImpl.createTestDelegators(AbstractTestSuiteChunkerImpl.java:217) 在 org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.(JUnit4TestSuiteChunkerImpl.java:59) 在 org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.(AbstractCommonPowerMockRunner.java:32) 在 org.powermock.modules.junit4.PowerMockRunner.(PowerMockRunner.java:33) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native 方法)在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:422) 在 org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:29) 在 org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:21) 在 org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59) 在 org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26) 在 org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59) 在 org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:26) 在 com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:41) 在 com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) 在 com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 引起:java.lang.ClassCastException: javassist.bytecode.InterfaceMethodrefInfo 不能强制转换为 javassist.bytecode.MethodrefInfo 在 javassist.bytecode.ConstPool.getMethodrefType(ConstPool.java:452) 在 javassist.bytecode.stackmap.Tracer.doInvokeMethod(Tracer.java:800) 在 javassist.bytecode.stackmap.Tracer.doOpcode148_201(Tracer.java:597) 在 javassist.bytecode.stackmap.Tracer.doOpcode(Tracer.java:81) 在 javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:187) 在 javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:199) 在 javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:164) 在 javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:108) 在 javassist.bytecode.MethodInfo.rebuildStackMap(MethodInfo.java:423) 在 javassist.bytecode.MethodInfo.rebuildStackMapIf6(MethodInfo.java:405) 在 javassist.CtBehavior.insertBefore(CtBehavior.java:768) 在 javassist.CtBehavior.insertBefore(CtBehavior.java:734) 在 org.powermock.core.transformers.impl.MainMockTransformer.modifyMethod(MainMockTransformer.java:206) 在 org.powermock.core.transformers.impl.MainMockTransformer.allowMockingOfStaticAndFinalAndNativeMethods(MainMockTransformer.java:142) 在 org.powermock.core.transformers.impl.MainMockTransformer.transform(MainMockTransformer.java:65) 在 org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:215) ... 56 更多

【问题讨论】:

    标签: java javafx junit powermock


    【解决方案1】:

    很遗憾,如果您确实需要准备测试ToplevelPane 课程,现在无法解决此问题。但我不确定它是否需要。 我注意到ToplevelPane 类没有静态或最终方法。如果从注解中删除ToplevelPane,则测试失败并出现另一个错误。

    java.lang.ExceptionInInitializerError 在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(本机方法) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:423) 在 java.lang.Class.newInstance(Class.java:442) 在 sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51) 在 javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1009) 在 javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:746) 在 javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707) 在 javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527) 在 javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441) 在 javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409) 在 nl.utwente.viskell.ui.ComponentLoader.loadFXML(ComponentLoader.java:25) 在 nl.utwente.viskell.ui.components.ValueBlock.(ValueBlock.java:48) 在 nl.utwente.viskell.ui.components.ConstantBlock.(ConstantBlock.java:25) 在 ValueBlockTest.outputTest(ValueBlockTest.java:33) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:316) 在 org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89) 在 org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:300) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:288) 在 org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) 在 org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:208) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:147) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:121) 在 org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 在 org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:123) 在 org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:123) 在 org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 在 org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) 在 org.junit.runner.JUnitCore.run(JUnitCore.java:137) 在 com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) 在 com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234) 在 com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) 原因:java.lang.IllegalStateException:工具包未初始化 在 com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273) 在 com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268) 在 com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:550) 在 com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:512) 在 javafx.scene.control.Control.(Control.java:87) ... 51 更多

    如果将 Javassist 更新到最新版本,则 CgLib 会创建奇怪的代理类以使用 Javassist 代码进行修改,因此 JVM 会抛出 java.lang.VerifyError。 Mockito 1 和 PowerMock 使用不再支持的 cglib 2。

    Mockito 自版本 2 起已迁移到 ByteButty,但它只是测试版。 PowerMock 也将迁移到 ByteButty,但我怀疑它会早于 6 月底。

    我将尝试在下一个 PowerMock 版本 (1.6.5) 中解决此问题,但我不确定它是否可行。

    我在我们的错误跟踪器中创建了一个issue。顺便说一句,如果 javafx.scene.layout.Region 被嘲笑,我可以重现该问题。

    【讨论】:

    • 非常感谢亚瑟的回复。在使用其他版本时,我确实遇到了 VerifyErrors。这可以避免在执行测试时将 --noverify 传递给 JVM,但我不想在这个项目上走那条路……无论如何我可以加注/关注一个项目或发布对这个特定项目的更新?跨度>
    • 我在我们的错误跟踪器中创建了一个issue。顺便说一句,我发现没有理由准备测试 ToplevelPane 。正如我在源代码中看到的那样,ToplevelPane 类没有静态或最终方法。如果从注释中删除ToplevelPane,则测试失败并出现另一个错误。如果 javafx.scene.layout.Region 被嘲笑,我也可以重现该问题。
    • 感谢您的问题,将跟踪它。我相信我需要准备 ToplevelPane 进行测试,如果我想用 whenNew() “捕捉” new() 对其他模拟类的调用(我在其他地方读过)。有些 FX 类还可以,有些则失败 - 不知道为什么......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多