CDI: Interceptor не вызывается при вызове из теста JUnit

Я создал перехватчик, следуя документации JBoss.

Чтобы проверить перехватчик, я положил:

@Interceptor
@Transactional
public class TransactionalInterceptor {
  @AroundInvoke
  public Object intercept(InvocationContext ctx) throws Exception {
    System.out.println("intercept!");
    return ctx.proceed();
  }
}

Теперь я хотел протестировать этот перехватчик в модульном тесте, используя класс WeldJUnit4Runner.

@RunWith(WeldJUnit4Runner.class)
public class MyTest {
  @Test
  @Transactional  // the interceptor I created
  public void testMethod() {
    System.out.println("testMethod");
    anotherMethod();
  }

  @Transactional
  public void anotherMethod() {
    System.out.println("anotherMethod");
  }
}

Теперь ожидаемый результат будет, конечно,

intercept!
testMethod
intercept!
anotherMethod

Но вместо этого вывод

intercept!
testMethod
anotherMethod

Основная проблема заключается в том, что это также верно, если я внедряю бин в свой тест: первый метод бина, который я вызываю, перехватывается, но если этот метод вызывает другой метод, перехватчик не вызывается.

Любые идеи очень ценятся!


Я просто попытался изменить свой код в соответствии с предложением @adrobisch, и это работает:

@RunWith(WeldJUnit4Runner.class)
public class MyTest {
  @Inject
  private MyTest instance;

  @Test
  @Transactional  // the interceptor I created
  public void testMethod() {
    System.out.println("testMethod");
    instance.anotherMethod();
  }

  @Transactional
  public void anotherMethod() {
    System.out.println("anotherMethod");
  }
}

Выход (как и ожидалось)

intercept!
testMethod
intercept!
anotherMethod

Однако следующее не работает:

@RunWith(WeldJUnit4Runner.class)
public class MyTest {
  @Inject
  private MyTest instance;

  @Test
  // @Transactional  <- no interceptor here!
  public void testMethod() {
    System.out.println("testMethod");
    instance.anotherMethod();
  }

  @Transactional
  public void anotherMethod() {
    System.out.println("anotherMethod");
  }
}

Выход здесь

testMethod
anotherMethod

Однако, это похоже на спецификацию! Теперь все хорошо.

2 ответа

Решение

Перехватчики реализованы с использованием прокси. Поскольку второй метод вызывается из экземпляра объекта, прокси-сервер не может отследить вызов и не может быть перехвачен. Для этого вам понадобится ссылка на CDI-прокси вашего компонента.

Можно запустить тесты на правильно инициализированном компоненте CDI с помощью DeltaSpike, хотя его документация и сообщения об ошибках не очень полезны, когда они не совсем верны. Вот как это сделать, чтобы перехватчик @Transactional работал:

@Transactional // the @Transactional from org.apache.deltaspike.jpa.api.transaction
@TestControl(startScopes = { TransactionScoped.class })
@RunWith(CdiTestRunner.class)
public MyTestClass { ... }

затем добавьте:

deltaspike.testcontrol.use_test_class_as_cdi_bean=true

в src/test/resources/META-INF/apache-deltaspike.properties

К сожалению, @Transactional(readOnly = true) не работает - понятия не имею, почему. И, в отличие от эквивалента Spring, он не откатит транзакцию и не запустит @Before/@After в той же транзакции.

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

Другие вопросы по тегам