SpringBootTest中标记@TestAnnotation的测试方法无法触发AOP@Aspect切面的@Around通知
我太懂你遇到的这个坑了——切面的构造函数日志能打出来,说明Spring确实加载了这个Bean,但就是死活拦截不到测试方法上的@TestAnnotation。这其实是Spring AOP的工作机制决定的:
Spring AOP默认是基于代理实现的,它只会对Spring容器管理的Bean的方法调用生效。而你的测试类MyTestClass虽然被@SpringBootTest标记,但测试方法的执行是由JUnit框架直接调用的,测试类本身并不会被Spring生成代理对象,所以AOP的环绕通知自然就抓不到测试方法的执行了。
下面给你两种可行的解决方案,你可以根据场景选:
方案一:把测试逻辑抽成Spring管理的Bean(推荐)
这种方法最贴合Spring的使用习惯,改动也最小。你只需要把测试里的核心逻辑放到一个被@Component标记的Bean中,在测试类里注入这个Bean并调用它的方法(给这个方法加@TestAnnotation),AOP就能正常拦截了。
比如先创建一个测试服务类:
@Component public class TestExecutor { @TestAnnotation public void runTestLogic() { System.out.println("测试核心逻辑执行中..."); } }
然后修改你的测试类,注入这个Bean并调用:
@SpringBootTest @TestPropertySource(value = "classpath:application-test.yml", factory = YamlPropertySourceFactory.class) @AutoConfigureMockMvc class MyTestClass { @Autowired private MockMvc mockMvc; @Autowired private TestExecutor testExecutor; @Test void testSomething() throws Exception { // 调用被Spring代理的Bean方法,AOP会拦截这个调用 testExecutor.runTestLogic(); System.out.println("testSomething() called."); // 原来的MockMvc测试逻辑 } }
这样一改,TestExecutor的runTestLogic方法是Spring代理对象的方法,切面的aroundAdvice就能正常触发了。
方案二:改用AspectJ织入(进阶)
如果你一定要直接拦截测试方法本身,可以放弃Spring AOP,改用AspectJ的加载时织入(LTW)。这种方式是直接修改字节码,能拦截所有方法调用,包括JUnit执行的测试方法,但配置会复杂一些:
- 先添加AspectJ依赖:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <scope>test</scope> </dependency>
- 在
src/test/resources下创建META-INF/aop.xml,配置织入规则:
<aspectj> <weaver> <include within="de.mycompany..*"/> <include within="org.springframework.boot.test.context..*"/> </weaver> <aspects> <aspect name="de.mycompany.aspect.TestAspect"/> </aspects> </aspectj>
- 给测试类添加
@EnableLoadTimeWeaving,或者在IDE的运行配置里添加VM参数:-javaagent:path/to/aspectjweaver.jar(需要对应你依赖里的weaver jar路径)。
不过这种方式配置成本高,还可能引入额外的复杂度,除非你有特殊需求,否则更推荐方案一。
另外提一句:你原来测试类里的@ComponentScan其实可以删掉——@SpringBootTest默认会扫描启动类所在包及其子包,只要你的启动类在de.mycompany下,就不需要额外指定basePackages了。
备注:内容来源于stack exchange,提问作者truj

