Spring Security Test中@WithMockUser注解不生效返回null问题
问题根因
@WithMockUser 是Spring Test生态提供的注解,依赖Spring测试上下文的监听器或对应扩展解析才能生效。你当前仅使用MockitoExtension运行纯Mockito单元测试,没有启动Spring测试相关的处理逻辑,因此注解不会生效,SecurityContextHolder中默认是空上下文。
解决方案
方案1:使用轻量SecurityContext扩展(推荐)
Spring Security 5.7及以上版本提供了独立的SecurityContextExtension,不需要启动完整Spring上下文,仅需引入即可支持@WithMockUser注解,改造成本极低。
- 确保项目已引入
spring-security-test依赖 - 修改测试类的扩展配置,同时保留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的逻辑封装为静态工具方法,每次测试仅需一行调用即可,避免重复编写样板代码:
- 编写通用工具类:
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(); } }
- 测试中直接调用:
@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
相关产品推荐
相关产品推荐

