java PowerMock和JavaAssist“未能转换类”
在使用PowerMock进行单元测试时,我遇到了一些特定类及其转换的问题
我已经看过很多这样的响应,并尝试了PowerMock、JUnit和JavaAssist(覆盖依赖项)的许多组合,但找不到适用于这个类的组合
(PowerMock、Junit和Javaassist的一些组合没有这个问题,但堆栈帧无效……因此也被卡住了——但我必须在一个单独的so问题中解决这个问题)
如果我将类ToplevelPanel包括在@PrepareForTest()列表中,那么它将失败。其他JavaFX类(比如Pane.class)不会引起任何问题
ToplevelPanel没有什么特别奇怪的地方:
public class ToplevelPane extends Region implements BlockContainer, Bundleable {
Bundleable没有@Serializable注释或任何特殊的内容
当我测试ToplevelPanel并希望它在@PrepareForTest中能够通过whenNew()捕获new()时,以及当我测试其他类并想要模拟它时,这都失败了
如果有人能分享pom。xml或版本组合,允许我@PrepareForTest这样的类,包括捕获whenNew()将不胜感激
在这篇文章的底部,你可以找到失败的堆栈跟踪
波姆。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: Failed to transform class with name nl.utwente.viskell.ui.ToplevelPane. Reason: javassist.bytecode.InterfaceMethodrefInfo cannot be cast to javassist.bytecode.MethodrefInfo at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:219) at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:147) at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:67) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114) at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125) at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49) at sun.reflect.annotation.AnnotationParser.parseSig(AnnotationParser.java:439) at sun.reflect.annotation.AnnotationParser.parseClassValue(AnnotationParser.java:420) at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:724) at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:531) at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355) at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286) at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120) at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72) at java.lang.Class.createAnnotationData(Class.java:3521) at java.lang.Class.annotationData(Class.java:3510) at java.lang.Class.getAnnotation(Class.java:3415) 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.(PowerMockJUnit44RunnerDelegateImpl.java:70) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl.(PowerMockJUnit47RunnerDelegateImpl.java:42) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl.(PowerMockJUnit49RunnerDelegateImpl.java:25) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:422) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:143) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.createDelegatorFromClassloader(JUnit4TestSuiteChunkerImpl.java:39) at org.powermock.tests.utils.impl.AbstractTestSuiteChunkerImpl.createTestDelegators(AbstractTestSuiteChunkerImpl.java:217) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.(JUnit4TestSuiteChunkerImpl.java:59) at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.(AbstractCommonPowerMockRunner.java:32) at org.powermock.modules.junit4.PowerMockRunner.(PowerMockRunner.java:33) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:422) 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 com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:41) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Caused by: java.lang.ClassCastException: javassist.bytecode.InterfaceMethodrefInfo cannot be cast to javassist.bytecode.MethodrefInfo at javassist.bytecode.ConstPool.getMethodrefType(ConstPool.java:452) at javassist.bytecode.stackmap.Tracer.doInvokeMethod(Tracer.java:800) at javassist.bytecode.stackmap.Tracer.doOpcode148_201(Tracer.java:597) at javassist.bytecode.stackmap.Tracer.doOpcode(Tracer.java:81) at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:187) at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:199) at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:164) at javassist.bytecode.stackmap.MapMaker.make(MapMaker.java:108) at javassist.bytecode.MethodInfo.rebuildStackMap(MethodInfo.java:423) at javassist.bytecode.MethodInfo.rebuildStackMapIf6(MethodInfo.java:405) at javassist.CtBehavior.insertBefore(CtBehavior.java:768) at javassist.CtBehavior.insertBefore(CtBehavior.java:734) at org.powermock.core.transformers.impl.MainMockTransformer.modifyMethod(MainMockTransformer.java:206) at org.powermock.core.transformers.impl.MainMockTransformer.allowMockingOfStaticAndFinalAndNativeMethods(MainMockTransformer.java:142) at org.powermock.core.transformers.impl.MainMockTransformer.transform(MainMockTransformer.java:65) at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:215) ... 56 more
# 1 楼答案
不幸的是,如果您真的需要准备测试
ToplevelPane
类,那么这个问题现在就无法解决。但我不确定是否需要。 我注意到ToplevelPane
类没有静态或final方法。如果从注释中删除ToplevelPane
,那么测试将失败,并出现另一个错误如果将Javassist更新到最新版本,那么CgLib会为使用Javassist代码进行修改创建奇怪的代理类,所以JVM会抛出
java.lang.VerifyError
。Mockito 1和PowerMock使用不再受支持的cglib 2Mockito从版本2开始就被迁移到了ByteButty,但它只是测试版。PowerMock也将搬到ByteButty,但我怀疑这是否会早于6月底
我将在下一个PowerMock版本(1.6.5)中尝试解决这个问题,但我不确定它是否可行
我在我们的bug追踪器中创建了一个issue。顺便说一下,如果
javafx.scene.layout.Region
被嘲笑,我可以重现这个问题