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 в той же транзакции.
Но для другого перехватчика, который вам нужен только вокруг самого метода тестирования, все должно быть в порядке.