如何为集成Spring Security的项目编写基于JUnit 5的单元测试?
方案说明
你当前的写法是否正确完全取决于你的测试目标,两种适配方案如下:
场景1:仅测试Controller层业务逻辑/接口权限规则,不需要验证自定义认证逻辑
这种场景下你现在的写法是完全合理的:@WebMvcTest 本身就是切片测试,默认只会加载指定Controller相关的Bean,你Mock掉AuthenticationService是为了避免依赖安全层的实现,只需要按测试场景Mock认证的返回结果即可:
- 测试需要认证通过的场景:Mock
authenticate方法返回带对应角色权限的Authentication对象 - 测试认证失败的场景:Mock
authenticate方法抛出AuthenticationException子类即可
场景2:需要将自定义AuthenticationProvider的认证逻辑也纳入测试范围
这种场景确实不该直接Mock AuthenticationService,你需要调整测试配置,引入安全配置类,只Mock AuthenticationService的底层依赖:
- 调整
PortfolioControllerTest配置:
@AutoConfigureMockMvc @AutoConfigureJsonTesters // 引入自定义的SecurityConfig配置类,避免被切片测试过滤 @WebMvcTest(value = PortfolioController.class, includeFilters = { @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class) }) public class PortfolioControllerTest { @Autowired private MockMvc mvc; @Autowired private JacksonTester<Portfolio> json; @MockBean private UserService userService; @MockBean private PortfolioService portfolioService; // 不再Mock AuthenticationService,改为Mock它的两个底层依赖 @MockBean private UserRepository userRepository; @MockBean private HashService hashService; // 测试方法里可以模拟userRepository、hashService的返回,验证真实的认证流程逻辑 }
- 单独为
AuthenticationService编写单元测试(更推荐,完全不需要Spring上下文,执行速度更快)
@ExtendWith(MockitoExtension.class) public class AuthenticationServiceTest { @Mock private UserRepository userRepository; @Mock private HashService hashService; @InjectMocks private AuthenticationService authenticationService; @Test public void authenticate_shouldReturnAuthenticatedToken_whenCredentialsValid() { // 构造入参UsernamePasswordAuthenticationToken // Mock userRepository.findByUsername返回匹配的用户实体 // Mock hashService.matches返回密码匹配结果 // 调用authenticate方法断言返回的认证对象符合预期 } @Test public void authenticate_shouldThrowException_whenPasswordWrong() { // 测试密码错误的异常分支逻辑 } @Test public void supports_shouldReturnTrue_forUsernamePasswordToken() { assertTrue(authenticationService.supports(UsernamePasswordAuthenticationToken.class)); } }
额外提示
如果你的测试不需要走完整的认证流程,只是要模拟某个已登录用户访问接口,可以直接用Spring Security提供的@WithMockUser注解修饰测试方法,指定用户名、角色即可,不需要手动Mock任何认证相关的Bean。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

