如何在MockMvc单元测试中为REST API传递非@PathVariable参数
解决MockMvc测试中UserContext空指针问题的几种方案
首先明确:UserContext一般是通过自定义参数解析器注入到接口方法参数中的,测试时需要模拟这个注入逻辑,以下是几种可行方案:
方案1:自定义模拟参数解析器并注册到MockMvc
如果项目通过HandlerMethodArgumentResolver解析UserContext,可以在MockMvc配置中添加模拟解析器,直接返回预设的UserContext实例:
// 创建并预设UserContext模拟对象 UserContext mockUserContext = Mockito.mock(UserContext.class); when(mockUserContext.getAppName()).thenReturn("test-app"); // 构建MockMvc时注册自定义参数解析器 this.mockMvc = MockMvcBuilders.standaloneSetup(yourControllerInstance) .setCustomArgumentResolvers(new HandlerMethodArgumentResolver() { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType().equals(UserContext.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { return mockUserContext; } }) // 必须添加Spring Security测试支持,处理@PreAuthorize注解 .apply(springSecurity()) .build(); // 执行测试请求 this.mockMvc.perform(get("/name/dummyName")) .andExpect(status().isOk());
方案2:用@MockBean注入模拟的UserContext
如果UserContext是通过Spring容器注入(比如控制器依赖容器中的UserContext实例),或者参数解析器依赖容器中的UserContext,可以直接用@MockBean模拟:
@SpringBootTest @AutoConfigureMockMvc public class NameControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserContext userContext; @Test void testGetName() throws Exception { // 预设mock行为 when(userContext.getAppName()).thenReturn("test-app"); // 模拟有权限的用户,同时执行请求 mockMvc.perform(get("/name/dummyName") .with(user("test-user").authorities("name.r"))) .andExpect(status().isOk()); } }
方案3:通过请求属性传递UserContext实例
如果你的参数解析器是从请求属性中获取UserContext,测试时可以直接往请求中添加属性:
@Test void testGetName() throws Exception { UserContext mockUserContext = Mockito.mock(UserContext.class); when(mockUserContext.getAppName()).thenReturn("test-app"); mockMvc.perform(get("/name/dummyName") .with(request -> { // 往请求中添加UserContext属性,匹配解析器的获取逻辑 request.setAttribute("userContext", mockUserContext); return request; }) .with(user("test-user").authorities("name.r"))) .andExpect(status().isOk()); }
关键注意事项
- 接口带有
@PreAuthorize("hasAuthority('name.r')"),测试时必须通过.with(user("xxx").authorities("name.r"))模拟拥有对应权限的用户,否则会返回403禁止访问。 - 要确保测试中传递
UserContext的方式和项目中参数解析器的逻辑一致,比如如果解析器是从SecurityContext提取信息,就要对应模拟SecurityContext中的数据。
内容的提问来源于stack exchange,提问作者Developer208
相关产品推荐
相关产品推荐

