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

Spring Boot单元测试中如何正确Mock SecurityContextHolder

问题原因

原测试代码运行失败有三个直接原因:

  • 变量名拼写错误:setUp方法中声明的Mock认证对象变量名为auth,但给SecurityContext打桩时传入的是未定义的authentication,会直接触发运行时错误。
  • 核心方法未打桩:Mock生成的Authentication实例没有配置getAuthorities()方法的返回值,Mockito默认对集合返回值返回空列表,业务代码中判断角色是否存在永远得到false,无法进入预期逻辑分支。
  • 缺少测试后清理逻辑:SecurityContextHolder基于ThreadLocal存储上下文,测试执行完成后如果不主动清空,上下文会残留到同线程执行的其他测试用例中,污染测试结果。
正确实现方案

方案1:纯Mockito手动Mock实现

适合不加载Spring上下文的纯单元测试场景,代码如下:

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.List;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class UserApiTest {

    @Before
    public void setUp() {
        // 构造当前测试场景需要的角色权限
        List<GrantedAuthority> testAuthorities = List.of(
                new SimpleGrantedAuthority("ROLE_roleName1")
        );
        // Mock认证对象,配置权限返回值
        Authentication auth = mock(Authentication.class);
        when(auth.getAuthorities()).thenReturn(testAuthorities);
        // Mock安全上下文,绑定认证对象
        SecurityContext securityContext = mock(SecurityContext.class);
        when(securityContext.getAuthentication()).thenReturn(auth);
        // 将上下文设置到Holder中
        SecurityContextHolder.setContext(securityContext);
    }

    @After
    public void tearDown() {
        // 测试完成后清空上下文,避免跨用例污染
        SecurityContextHolder.clearContext();
    }

    @Test
    public void testRole1BusinessLogic() {
        // 编写对应角色的接口测试逻辑即可
    }
}

如果要测试ROLE_roleName2的分支,只需要把setUp中构造的权限替换为对应角色即可,也可以根据不同测试用例单独构造上下文。

方案2:使用Spring Security Test注解实现(推荐)

如果是集成测试场景,推荐直接引入spring-security-test测试依赖,通过注解直接模拟登录用户,不需要手动编写Mock代码,出错概率更低:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserApiIntegrationTest {

    @Test
    @WithMockUser(roles = "roleName1")
    // 注意roles参数不需要手动加ROLE_前缀,框架会自动拼接
    public void testRole1Access() {
        // 直接发起接口请求测试逻辑,框架会自动填充SecurityContext
    }

    @Test
    @WithMockUser(roles = "roleName2")
    public void testRole2Access() {
        // 测试第二个角色的逻辑分支
    }
}

注意:如果需要配置非角色类的自定义权限,可以使用@WithMockUser(authorities = "CUSTOM_PERMISSION")直接传入完整权限字符串,框架不会自动拼接前缀。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 10:01:08