Spring Boot项目中无法测试SessionRegistry相关功能问题求助
问题根因排查
- 框架注解混用冲突
第一个测试类同时使用@SpringBootTest+@MockBean和Mockito的@InjectMocks+MockitoAnnotations.initMocks,两套注入逻辑互相覆盖:@MockBean已经将Mock实例注入到Spring上下文,MockitoAnnotations.initMocks会重新初始化测试类的字段,把registry替换为未初始化的实例,导致调用when时报“非Mock对象”异常,同时业务类中的SessionRegistry也未正确注入,触发空指针。 - Mock方法参数不匹配
你打桩getAllSessions时用的入参是自己new的Object object = new Object(),但实际业务代码里调用时传的是authentication.getPrincipal(),两个对象不是同一个实例,Mockito默认按equals匹配,所以打桩不生效,调用时返回空值。 - 字段注入兼容性问题
业务类AppLogoutHandler里SessionRegistry是用@Autowired直接注入私有字段,没有提供构造函数/setter方法,部分低版本Mockito对无构造注入的私有字段注入支持有问题,会导致注入失败。
正确解决方案(二选一即可)
方案1:纯单元测试(不启动Spring上下文,执行速度快)
使用MockitoJUnitRunner,不需要Spring相关注解:
@RunWith(MockitoJUnitRunner.class) public class AppLogoutSuccessHandlerTest { @Mock SessionRegistry registry; @InjectMocks AppLogoutHandler appLogoutHandler; @Mock Authentication authentication; @Mock HttpServletRequest request; @Mock HttpServletResponse response; @Test public void onLogoutSuccessTest() throws Exception { // 构造模拟返回值 List<SessionInformation> informations = new ArrayList<>(); // 按需添加模拟的SessionInformation // 模拟principal,和authentication.getPrincipal()返回的是同一个对象 Object mockPrincipal = new Object(); Mockito.when(authentication.getPrincipal()).thenReturn(mockPrincipal); Mockito.when(authentication.getDetails()).thenReturn(new Object()); // 打桩SessionRegistry,用和上面相同的mockPrincipal作为入参 Mockito.doReturn(informations).when(registry).getAllSessions(mockPrincipal, false); // 调用测试方法 appLogoutHandler.onLogoutSuccess(request, response, authentication); // 补充你的断言逻辑 } }
如果还是注入失败,给AppLogoutHandler换成Spring推荐的构造函数注入,兼容所有版本Mockito:
@Component public class AppLogoutHandler implements LogoutSuccessHandler{ private final SessionRegistry sessionRegistry; // Spring 4.3+ 单构造函数无需加@Autowired public AppLogoutHandler(SessionRegistry sessionRegistry) { this.sessionRegistry = sessionRegistry; } // 其余原有逻辑保持不变 }
方案2:Spring集成测试(启动Spring上下文)
使用@SpringBootTest,不要混用Mockito的@InjectMocks和initMocks:
@RunWith(SpringRunner.class) @SpringBootTest public class AppLogoutSuccessHandlerTest { @MockBean SessionRegistry registry; @Autowired AppLogoutHandler appLogoutHandler; // 直接从Spring上下文取业务类,@MockBean会自动替换上下文中的SessionRegistry @Mock Authentication authentication; @Mock HttpServletRequest request; @Mock HttpServletResponse response; @Test public void onLogoutSuccessTest() throws Exception { // 和方案1保持一致的打桩逻辑,保证入参匹配 Object mockPrincipal = new Object(); Mockito.when(authentication.getPrincipal()).thenReturn(mockPrincipal); Mockito.when(authentication.getDetails()).thenReturn(new Object()); Mockito.doReturn(new ArrayList<>()).when(registry).getAllSessions(mockPrincipal, false); appLogoutHandler.onLogoutSuccess(request, response, authentication); // 补充你的断言逻辑 } }
内容的提问来源于stack exchange,提问作者Siddharth Chaurasia
相关产品推荐
相关产品推荐

