Mockito Spy触发真实方法调用致NPE及实例变量监视问题求助
解决Mockito Spy触发真实方法导致NPE的问题
看起来你遇到的问题是在用Mockito Spy模拟AuthenticationSessionManager时,意外触发了真实的getCurrentAuthenticationSession方法调用,进而因为依赖的实例状态不全(比如session可能未正确初始化)抛出了空指针异常。我来帮你拆解问题并给出解决方案:
问题根源分析
你使用Mockito.spy(new AuthenticationSessionManager(session))创建Spy对象时,真实的AuthenticationSessionManager构造函数会被执行,如果传入的session是null或者未被正确mock的实例,那么这个真实对象的内部状态就会有问题。另外,即使Spy创建成功,如果你的参数匹配器和方法实际参数类型不匹配,Mockito也会跳过拦截,转而执行真实方法,最终导致NPE。
解决方案
方案1:优先使用Mock而非Spy(推荐)
如果你不需要保留AuthenticationSessionManager的任何真实逻辑,完全用模拟对象替代的话,直接使用mock比spy更安全,因为它不会触发任何真实代码:
// 先mock依赖的HttpSession,确保它能满足后续需求 HttpSession session = Mockito.mock(HttpSession.class); // 直接创建AuthenticationSessionManager的mock实例,无需真实构造 AuthenticationSessionManager authSessionManager = Mockito.mock(AuthenticationSessionManager.class); // 设置方法调用的返回值,注意参数匹配器要对应真实方法的参数类型 Mockito.doReturn(authenticationSessionModel) .when(authSessionManager) .getCurrentAuthenticationSession(any(Realm.class), any(Client.class), anyString());
之后你需要把这个mock实例注入到业务代码中(比如通过依赖注入框架,或者用反射替换原有的实例),这样业务代码调用时就会直接返回你预设的authenticationSessionModel,不会触发真实方法。
方案2:正确使用Spy(仅当需要保留部分真实逻辑时)
如果你确实需要保留AuthenticationSessionManager的部分真实行为,那必须确保Spy的真实对象状态是有效的:
// 第一步:完全mock依赖的session,确保它的所有必要方法都有预设行为 HttpSession session = Mockito.mock(HttpSession.class); // 比如如果session需要返回某个属性,可以提前设置 Mockito.when(session.getAttribute("someKey")).thenReturn("mockValue"); // 第二步:创建Spy对象,此时真实构造函数执行时依赖的session是可用的mock AuthenticationSessionManager spyAuthSessionManager = Mockito.spy(new AuthenticationSessionManager(session)); // 第三步:拦截目标方法,确保参数匹配器完全匹配方法参数类型 Mockito.doReturn(authenticationSessionModel) .when(spyAuthSessionManager) .getCurrentAuthenticationSession(any(Realm.class), any(Client.class), anyString());
关键注意事项
- 避免使用
when(spy.xxx()).thenReturn(...)语法:这种写法会先调用一次真实的xxx()方法,这往往是导致NPE的隐形原因,一定要用doReturn(...).when(spy).xxx(...)来拦截。 - 参数匹配器要精准:
any()是泛型匹配,如果方法参数是具体类型(比如Realm、Client),最好用any(Realm.class)、any(Client.class)明确指定,避免因为类型不匹配导致Mockito无法拦截方法。 - Spy的真实对象必须状态完整:Spy的本质是包裹真实对象,所以真实对象的所有依赖都必须能正常工作,否则调用真实方法时必然会抛出异常。
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

