You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 15:22:49