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

Spring Security Test中@WithMockUser注解不生效返回null问题

问题根因

@WithMockUser 是Spring Test生态提供的注解,依赖Spring测试上下文的监听器或对应扩展解析才能生效。你当前仅使用MockitoExtension运行纯Mockito单元测试,没有启动Spring测试相关的处理逻辑,因此注解不会生效,SecurityContextHolder中默认是空上下文。

解决方案

方案1:使用轻量SecurityContext扩展(推荐)

Spring Security 5.7及以上版本提供了独立的SecurityContextExtension,不需要启动完整Spring上下文,仅需引入即可支持@WithMockUser注解,改造成本极低。

  1. 确保项目已引入spring-security-test依赖
  2. 修改测试类的扩展配置,同时保留Mockito扩展能力,调整后测试类代码如下:
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.test.context.support.SecurityContextExtension;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mock;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@ExtendWith({MockitoExtension.class, SecurityContextExtension.class})
public class SegmetnServiceTest {
    
    @InjectMocks
    private SegmentService service;

    @Mock
    private SegmentRepository repository; // 必须补充Repository的Mock声明,否则会空指针

    @Test
    @WithMockUser(username = "test_user_id")
    void testWithMockUser() {
            //given
            UpdateSegmentReq request = new UpdateSegmentReq();
            String name = "TEST";
            request.setName(name);
            // 配置Repository的Mock返回
            SegmentNode mockNode = new SegmentNode();
            when(repository.findByCode(any())).thenReturn(mockNode);

            //when
            SegmentNode segment = service.updateSegment(request.getCode());

            //then
            assertEquals(segment.getName(), name);
            assertEquals("test_user_id", segment.getUpdatedBy());
    }
}

该扩展会自动在测试执行前注入模拟认证信息,测试结束后自动清空上下文,避免污染其他测试。如果使用的Spring Security版本低于5.7,无法使用SecurityContextExtension,直接选择方案2即可。

方案2:封装通用模拟方法

如果你不想引入额外扩展,可以把手动Mock的逻辑封装为静态工具方法,每次测试仅需一行调用即可,避免重复编写样板代码:

  1. 编写通用工具类:
import org.mockito.Mockito;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import static org.mockito.Mockito.when;

public class SecurityMockUtils {
    public static void mockCurrentUser(String userId) {
        Authentication authentication = Mockito.mock(Authentication.class);
        when(authentication.getPrincipal()).thenReturn(userId);
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    public static void clearContext() {
        SecurityContextHolder.clearContext();
    }
}
  1. 测试中直接调用:
@Test
void testWithMockUser() {
        //given
        SecurityMockUtils.mockCurrentUser("test_user_id");
        UpdateSegmentReq request = new UpdateSegmentReq();
        String name = "TEST";
        request.setName(name);
        SegmentNode mockNode = new SegmentNode();
        when(repository.findByCode(any())).thenReturn(mockNode);

        //when
        SegmentNode segment = service.updateSegment(request.getCode());

        //then
        assertEquals(segment.getName(), name);
        SecurityMockUtils.clearContext(); // 测试结束清理上下文
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 15:57:04