Spring Boot中MockMvc测试@ControllerAdvice的问题求助
我来帮你拆解下这个问题的核心原因,以及对应的解决办法~
为什么会出现两种矛盾的测试结果?
1. 注释setup()时的情况
当你使用@WebMvcTest(RunController.class)注解时,它的默认行为是只自动加载指定的RunController,而你的ExceptionHandlers(带@ControllerAdvice注解的全局异常处理器)并不会被自动纳入测试上下文。
所以当第二个测试中runService.getRuns()返回空列表时,假设你的Controller此时会抛出RunNotFoundException,但因为没有对应的异常处理器,Spring MVC会返回默认的错误响应,而非你自定义的404状态码,导致测试失败。而第一个测试是正常返回数据,不需要异常处理,所以能顺利通过。
2. 取消注释setup()时的情况
你的setup()方法里有个致命错误:MockMvcBuilders.standaloneSetup(runService)——standaloneSetup方法需要传入的是Controller实例,而不是Service对象!你把runService传进去,相当于没有正确配置RunController,第一个测试请求/api/runs时根本找不到对应的处理方法,自然失败。
不过你手动调用了setControllerAdvice(new ExceptionHandlers()),所以异常处理逻辑是生效的,这才让第二个测试通过,但这是建立在Controller配置错误的基础上的。
两种可行的解决方案
方案一:让@WebMvcTest加载全局异常处理器
最简单的方式是在测试类上添加@Import(ExceptionHandlers.class),让测试上下文包含你的异常处理器:
@RunWith(SpringRunner.class) @WebMvcTest(RunController.class) @Import(ExceptionHandlers.class) // 新增这行,导入异常处理器 public class RunControllerTest { @Autowired private MockMvc mvc; @MockBean private RunService runService; // 移除错误的setup方法 // 你的测试用例保持不变 }
这样既不需要手动构建MockMvc,又能让异常处理逻辑生效,两个测试都能正常通过。
方案二:修正setup()方法的配置
如果你更倾向于手动构建MockMvc,需要正确传入RunController实例,并确保mock的runService被注入到Controller中:
@RunWith(SpringRunner.class) @WebMvcTest(RunController.class) public class RunControllerTest { private MockMvc mvc; @MockBean private RunService runService; @Autowired private RunController runController; // 自动注入Controller实例 @Before public void setup() { this.mvc = MockMvcBuilders.standaloneSetup(runController) // 传入Controller而非Service .setControllerAdvice(new ExceptionHandlers()) .build(); } // 你的测试用例保持不变 }
这种方式手动配置MockMvc,同时保证Controller和异常处理器都能正常工作。
额外提醒
别忘了确认你的RunController中,当runService.getRuns()返回空列表时,确实会抛出RunNotFoundException——这是第二个测试能触发异常处理的前提哦!
内容的提问来源于stack exchange,提问作者derirative23

