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

Spring Security JWT测试中MockMvc无法Mock Service的解决方法

Spring Security JWT单元测试Mock Service不生效的解决方案

核心问题分析

你遇到的Mock Service不生效,本质是测试环境没有将Mock实例注入到Controller中,且若使用@SpringBootTest加载完整Spring上下文,会初始化真实的DataImporterService,同时Security配置的拦截逻辑也会干扰测试流程。下面是针对性的解决步骤:


1. 用@WebMvcTest+@MockBean构建隔离的Controller测试

@WebMvcTest仅加载Spring MVC相关组件(Controller、Converter、Filter等),不会初始化完整业务服务层,配合@MockBean可直接替换Controller依赖的DataImporterService为Mock实例,确保when()配置生效。

测试类示例

@WebMvcTest(ImportController.class) // 替换为你的实际Controller类名
@AutoConfigureMockMvc
class ImportControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean // 自动将此Mock实例注入到目标Controller中
    private DataImporterService dataImporterService;

    @Autowired
    private ObjectMapper objectMapper;

    // 测试场景3:令牌及权限正确时返回200
    @Test
    void validJwtAndPermission_returns200() throws Exception {
        // 1. 配置Mock Service的行为
        ImportRequest requestBody = new ImportRequest();
        // 若参数匹配失败,可改用any(ImportRequest.class)放宽匹配条件
        when(dataImporterService.doImport(requestBody)).thenReturn(ImportResult.success());

        // 2. 模拟携带有效JWT的请求
        mockMvc.perform(post("/api/import")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(requestBody))
                        .header("Authorization", "Bearer " + generateValidJwtWithImportPermission()))
                .andExpect(status().isOk());
    }

    // 辅助方法:生成带正确权限的测试JWT
    private String generateValidJwtWithImportPermission() {
        // 生成符合你项目JWT规则的测试令牌,包含所需权限
        return Jwts.builder()
                .setSubject("test-user")
                .claim("authorities", Collections.singletonList("IMPORT_DATA")) // 替换为你的权限标识
                .signWith(SignatureAlgorithm.HS256, "your-test-secret") // 替换为SecurityConfig中使用的密钥
                .compact();
    }
}

2. 处理Spring Security的拦截逻辑

如果你的SecurityConfig中配置了JWT过滤器,可选择两种方式处理:

  • 直接生成符合规则的测试JWT(如上例),让真实过滤器解析认证;
  • Mock认证过滤器,跳过令牌验证,直接设置认证上下文:

Mock认证过滤器的示例

@WebMvcTest(ImportController.class)
@AutoConfigureMockMvc
class ImportControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private DataImporterService dataImporterService;

    @MockBean // Mock JWT认证过滤器,直接设置认证上下文
    private JwtAuthenticationFilter jwtAuthenticationFilter;

    @BeforeEach
    void setUp() {
        // 构造拥有正确权限的认证对象
        Authentication authenticatedUser = UsernamePasswordAuthenticationToken.authenticated(
                "test-user",
                null,
                Collections.singletonList(new SimpleGrantedAuthority("IMPORT_DATA"))
        );

        // 模拟过滤器逻辑:直接将认证对象放入Security上下文
        when(jwtAuthenticationFilter.doFilterInternal(
                any(HttpServletRequest.class),
                any(HttpServletResponse.class),
                any(FilterChain.class)
        )).thenAnswer(invocation -> {
            SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
            // 执行后续过滤器链
            invocation.getArgument(2).doFilter(
                    invocation.getArgument(0),
                    invocation.getArgument(1)
            );
            return null;
        });
    }

    // 测试方法同上...
}

3. 确保Mock参数匹配正确

如果when()配置仍不生效,检查参数匹配逻辑:

  • 若ImportRequest未正确实现equals()方法,直接用对象实例匹配会失败,可改用any(ImportRequest.class);
  • 复杂参数可使用ArgumentMatchers.argThat()自定义匹配规则。

内容的提问来源于stack exchange,提问作者Jonathan Hagen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 15:41:46