Wicket 9单元测试用Mockito模拟HttpSession时getLoginName空指针问题
问题根因
- 你创建的mock
SecureWebSession实例未绑定到WicketTester运行上下文,Wicket处理请求时仍自动创建原生SecureWebSession实例,mock对象完全未生效 - 原生
SecureWebSession构造方法调用getSession(false)时,测试环境下此时还没有已创建的HttpSession,因此返回null,后续调用getLoginName触发空指针
推荐解决方案(最轻量,符合单元测试逻辑)
直接mock getLoginName 方法绕开内部实现,不需要处理HttpSession相关逻辑:
- 给你已创建的mock
SecureWebSession增加方法stub配置,指定getLoginName返回测试值 - 将mock的
SecureWebSession绑定到WicketTester上下文,替换Wicket自动生成的原生session - 移除冗余的MockHttpServletRequest、MockHttpSession相关配置,完全不需要用到
修改后的setUp核心代码如下:
@BeforeEach public void setUp() { // 原有SecurityContext配置保留 Authentication authentication = Mockito.mock(Authentication.class); SecurityContext securityContext = Mockito.mock(SecurityContext.class); Mockito.when(securityContext.getAuthentication()).thenReturn(authentication); Mockito.when(authentication.isAuthenticated()).thenReturn(true); SecurityContextHolder.setContext(securityContext); // 构造mock的SecureWebSession,配置所有需要的方法 SecureWebSession secureWebSession = Mockito.mock(SecureWebSession.class); Roles roles = new Roles(); roles.add("SUPER_ADMIN"); Mockito.when(secureWebSession.getRoles()).thenReturn(roles); // 新增这行,直接指定getLoginName返回测试值,完全绕开内部httpSession逻辑 Mockito.when(secureWebSession.getLoginName()).thenReturn("test"); tester = new WicketTester(webApplication); // 新增这行,把mock的session绑定到tester上下文 tester.setSession(secureWebSession); }
备选方案(需使用原生SecureWebSession实现时使用)
如果你的测试需要验证SecureWebSession本身的逻辑,不能mock整个类,可通过提前初始化HttpSession解决空指针:
- 测试时使用自定义的WebApplication子类,重写
newSession方法,在创建Session前提前初始化HttpSession,保证getSession(false)能拿到实例 - 再往HttpSession中写入
loginName属性即可
@BeforeEach public void setUp() { // 原有SecurityContext配置保留 Authentication authentication = Mockito.mock(Authentication.class); SecurityContext securityContext = Mockito.mock(SecurityContext.class); Mockito.when(securityContext.getAuthentication()).thenReturn(authentication); Mockito.when(authentication.isAuthenticated()).thenReturn(true); SecurityContextHolder.setContext(securityContext); // 自定义测试用WebApplication,提前创建HttpSession WebApplication testApp = new MyWicketApplication() { @Override public Session newSession(Request request, Response response) { MockHttpServletRequest containerReq = (MockHttpServletRequest) request.getContainerRequest(); // 提前创建session,让后续getSession(false)可返回非null值 containerReq.getSession(true); containerReq.getSession().setAttribute("loginName", "test"); return super.newSession(request, response); } }; tester = new WicketTester(testApp); }
注意事项
- Wicket Session与请求周期强绑定,必须在调用
startPage前完成session的绑定/配置,否则Wicket会自动创建原生Session覆盖你的配置 - 单元测试场景优先选用第一种方案,只mock当前测试依赖的外部方法,不需要关心
SecureWebSession的内部实现,测试逻辑更简洁可维护
内容的提问来源于stack exchange,提问作者miroana
相关产品推荐
相关产品推荐

