Ошибка сброса ByteBuddy при работе с Eclipse (EclEmma/JaCoCo) Покрытие кода

Я переопределяю классы с помощью ByteBuddy в модульном тесте. Я сбрасываю класс после каждого теста, чтобы избежать перекрестных помех между тестами.

ByteBuddy работает, как и ожидалось, при простом запуске тестов в Eclipse IDE или при работе с командной строкой maven. Но если он работает в Eclipse с покрытием, сброс класса приводит к следующему исключению:

java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)

Ниже приведен пример теста, который проходит в исполнителе JUnit по умолчанию, но не работает при запуске с покрытием кода в Eclipse. Ниже приведена полная трассировка стека сбоя.

Я использую ByteBuddy версии 1.8.22 и пакет покрытия кода Java EclEmma версии 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)

person NaderNader    schedule 16.09.2018    source источник
comment
Есть шанс, что другие агенты не совместимы с ретрансформацией. Если у вас есть только один такой агент на вашей виртуальной машине, и если вы повторно преобразуете классы, измененные этим агентом, вы получите эту ошибку. Невозможно обойти это, если другой агент несовместим.   -  person Rafael Winterhalter    schedule 17.09.2018


Ответы (1)


Я понял, что моя проблема была вызвана более старой версией ByteBuddy. Я получал версию 1.6.14 в своем проекте от Mockito. Когда я явно добавил ByteBuddy версии 1.8.22, тест проходит успешно как с покрытием, так и без него.

person NaderNader    schedule 16.09.2018