如何测试带有@Secured注解且实现接口的Spring Rest Controller?
解决
@WebMvcTest无法识别带@Secured注解且实现接口的REST控制器问题 问题概述
当REST控制器同时满足以下两个条件时:
- 实现了某个接口
- 类上标注了
@Secured注解
使用@WebMvcTest编写单元测试会出现控制器无法被识别的情况,测试请求返回404状态码。但只要移除@Secured注解,或者让控制器不实现接口,测试就能正常返回200;且实际应用运行时,两种控制器都能被正常识别。
通过注入RequestMappingHandlerMapping可发现,带接口继承关系的控制器并未被绑定到请求映射上,这是测试上下文特有的问题。
可行解决方案
1. 手动注册请求映射到测试上下文
在测试类中,手动将目标控制器的请求映射注册到RequestMappingHandlerMapping中,确保测试上下文能找到对应的处理方法:
@WebMvcTest(FailingTestController.class) @EnableGlobalMethodSecurity(securedEnabled = true) class FailingTestControllerTest { @Autowired private MockMvc mockMvc; @Autowired private RequestMappingHandlerMapping handlerMapping; @Autowired private FailingTestController failingTestController; @BeforeEach void setup() throws NoSuchMethodException { // 构建对应请求的映射信息 RequestMappingInfo mappingInfo = RequestMappingInfo .paths("/api/v1/password") .methods(HttpMethod.PUT) .build(); // 获取控制器中的处理方法 Method method = FailingTestController.class.getMethod("updatePassword", String.class); // 注册映射 handlerMapping.registerMapping(mappingInfo, failingTestController, method); } @Test void updatePassword_shouldReturnOk() throws Exception { mockMvc.perform(put("/api/v1/password") .param("newPassword", "testPass123")) .andExpect(status().isOk()); } }
2. 改用完整Spring上下文测试
如果测试需要依赖完整的安全配置或其他上下文组件,可以用@SpringBootTest配合@AutoConfigureMockMvc替代@WebMvcTest,这样能完整加载所有控制器配置:
@SpringBootTest @AutoConfigureMockMvc @EnableGlobalMethodSecurity(securedEnabled = true) class FailingTestControllerTest { @Autowired private MockMvc mockMvc; @Test void updatePassword_shouldReturnOk() throws Exception { mockMvc.perform(put("/api/v1/password") .param("newPassword", "testPass123")) .andExpect(status().isOk()); } }
3. 调整@Secured注解的位置
将@Secured注解从类级别移到具体的请求处理方法上,部分场景下可以触发测试上下文正确绑定请求映射:
@RestController public class FailingTestController implements MyPasswordApi { @Override @Secured("ROLE_USER") @PutMapping("/api/v1/password") public ResponseEntity<Void> updatePassword(@RequestParam String newPassword) { // 业务逻辑实现 return ResponseEntity.ok().build(); } }
内容的提问来源于stack exchange,提问作者Nils Bokermann
相关产品推荐
相关产品推荐

