我正在用单元测试中的ByteBuddy重新定义类。我会在每次测试后重置班级,以确保测试之间不会发生串扰。
当仅在Eclipse IDE中运行测试或使用maven命令行运行时,ByteBuddy可以按预期工作。但是,如果它在具有覆盖范围的Eclipse中运行,则重置类会导致以下异常:
java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
Bellow是一个示例测试,它通过了默认的JUnit运行器,但是在Eclipse中使用Code Coverage运行时失败。下面是故障的完整堆栈跟踪。
我正在使用ByteBuddy版本1.8.22和EclEmma Java代码覆盖程序包版本3.1.0.201804041601。
我假设此问题是由于ByteBuddy类修改与EclEmma代码检测之间的冲突引起的。是否有替代的方法来还原类定义,从而解决该问题?
涵盖范围内的失败:
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.FixedValue;
public class ByteBuddyEclEmmaTest {
@Test
public void recreateEclEmmaByteBuddyResetIssue() throws Exception {
ByteBuddyAgent.install();
ByteBuddy byteBuddy = new ByteBuddy();
ClassReloadingStrategy classReloadingStrategy = ClassReloadingStrategy.fromInstalledAgent();
byteBuddy
.redefine(X.class)
.method(named("getValue")).intercept(FixedValue.value("faked value"))
.make()
.load(X.class.getClassLoader(), classReloadingStrategy);
X x = new X();
assertThat(x.getValue()).isEqualTo("faked value");
classReloadingStrategy.reset(X.class);
assertThat(x.getValue()).isEqualTo("real value");
}
public class X {
public String getValue() {
return "real value";
}
}
}
堆栈跟踪:
java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)
at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy$Strategy$1.apply(ClassReloadingStrategy.java:261)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy$Strategy$1.reset(ClassReloadingStrategy.java:279)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy.reset(ClassReloadingStrategy.java:209)
at net.bytebuddy.dynamic.loading.ClassReloadingStrategy.reset(ClassReloadingStrategy.java:195)
at ByteBuddyEclEmmaTest.recreateEclEmmaByteBuddyResetIssue(ByteBuddyEclEmmaTest.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
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 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
答案 0 :(得分:2)
我发现我的问题是由ByteBuddy的旧版本引起的。我正在从Mockito提取1.6.14版本到我的项目中。当我明确引入ByteBuddy版本1.8.22时,无论是否覆盖,测试都可以成功运行。