I'm using spring-boot 3.4.2.
I want to use AOP aspects in order to modify annotations that I use in a spring boot test.
However my @Around method is not triggered during test execution. If I annotate e.g. an endpoint method inside a rest controller, than it is triggered. But I want to use it for tests.
Here's my annotation:
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}
Here's my Aspect:
@Aspect
@Component
public class TestAspect {
public TestAspect() {
// this is called - so @Component works
System.out.println("aspect constructor called");
}
@Around("@annotation(TestAnnotation)")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
// this is NOT called in the test - @Around did not work
System.out.println("aroundAdvice() called");
return joinPoint.proceed();
}
}
And here's my test:
@SpringBootTest
@ComponentScan(basePackages = { "de.mycompany" }) // root of all my packages
@TestPropertySource(value = "classpath:application-test.yml", factory = YamlPropertySourceFactory.class)
@AutoConfigureMockMvc
class MyTestClass {
@Autowired
private MockMvc mockMvc;
@Test
@TestAnnotation
void testSomething() throws Exception {
System.out.println("testSomething() called.");
// test something with mockMvc
}
}
If I annotate an endpoint in a RestController, aroundAdvice()
will be triggered, whenever that endpoint is called or tested.
But I need it to be triggered when my test method (here: testSomething()
) is called. And that does not work.
Using the fully qualified class in @Around
doesn't work either:
@Around("@annotation(de.mycompany.annotation.TestAnnotation)")
Annotations only work on beans. They work by creating proxy. Your MyTestClass
is not real Spring bean.
One way to implement what you want is to implement extension and check for annotation in InvocationInterceptor
.
public class MyExtension implements InvocationInterceptor {
public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
doMyStuff(invocationContext);
invocation.proceed();
}
public <T> T interceptTestFactoryMethod(Invocation<T> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
doMyStuff(invocationContext);
return invocation.proceed();
}
public void interceptTestTemplateMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
doMyStuff(invocationContext);
invocation.proceed();
}
void doMyStuff(ReflectiveInvocationContext<Method> invocationContext) {
Method m = invocationContext.getExecutable();
TestAnnotation a = m.getAnnotation(TestAnnotation .class);
if(a != null){
System.out.println("Here we go");
}
}
}
Put that extension on your test by adding @ExtendWith(MyExtension.class)
to your test class.