You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mockito中Mock方法返回空指针异常该如何解决?

解决Mockito深Stub引发的空指针异常问题

嘿,我来帮你搞定这个Mockito的空指针问题!先看看你贴的测试代码片段:

// Setup mocks 
private GoalService goalService; 
private Principal principal; 
private Goal goal; 
private SecurityService securityService; 

@Before 
public void setup() { 
    goalService = new GoalService(); 
    principal = mock(Principal.class); 
    goal = mock(Goal.class); 
    securityService = mock(SecurityService.class, Mockito.RETURNS_DEEP_STUBS); 
} 

@Test 
public void testRequesterOwnsGoalIsTrue() { 
    doReturn(1).when(securityService).getUserIdByPrincip... 
    // 后续业务逻辑调用
}

从代码来看,空指针异常大概率是深Stub(RETURNS_DEEP_STUBS)的使用方式不对导致的,我给你梳理几个排查和解决的方向:

1. 确保完整的方法调用链被正确打桩

你代码里的getUserIdByPrincip...明显没写完,这肯定会出问题!如果你的业务逻辑里是调用securityService.getUserIdByPrincipal(principal),那打桩必须写全整个方法签名:

doReturn(1).when(securityService).getUserIdByPrincipal(principal);

如果是更深的链式调用(比如securityService.userManager.getUserId(principal)),那深Stub要求你在打桩时就写出完整的调用链,不能只打桩中间层,比如:

doReturn(1).when(securityService).userManager.getUserId(principal);

2. 检查是否真的需要用深Stub

RETURNS_DEEP_STUBS是为链式调用场景设计的,但如果你的SecurityService只是普通的服务类,getUserIdByPrincipal是直接返回值的方法,那完全没必要用深Stub!改用普通mock反而更简单,还能避免不必要的问题:

// 去掉RETURNS_DEEP_STUBS,用普通mock初始化
securityService = mock(SecurityService.class);

3. 避免打桩语法混用错误

如果你用的是doReturn(...).when(...)语法,要确保括号里的对象和方法调用是正确的——不要把when(securityService.getUserIdByPrincipal(principal)).thenReturn(1)和doReturn(1).when(securityService).getUserIdByPrincipal(principal)混写错,后者才是doReturn的正确写法。

4. 排查是否有未打桩的方法调用

深Stub的特性是:如果调用了未打桩的链式方法,会返回默认的mock对象(或者null,如果是基本类型的包装类)。如果你的测试中调用了securityService的其他未打桩方法,就可能触发空指针。所以要确保测试中用到的所有方法都被正确打桩。

给你一个完整的正确示例参考:

@Before
public void setup() {
    goalService = new GoalService();
    principal = mock(Principal.class);
    goal = mock(Goal.class);
    // 只有当有链式调用时才用深Stub
    securityService = mock(SecurityService.class, Mockito.RETURNS_DEEP_STUBS);
    // 完整打桩链式调用
    doReturn(1).when(securityService).getUserContext().getUserId(principal);
}

@Test
public void testRequesterOwnsGoalIsTrue() {
    // 假设业务逻辑里调用了securityService.getUserContext().getUserId(principal)
    boolean isOwner = goalService.verifyGoalOwner(principal, goal);
    assertTrue(isOwner);
}

最后提醒一句:除非真的需要处理多层链式调用,否则尽量不用深Stub——它会让测试代码更复杂,也容易隐藏逻辑问题,优先用普通mock只打桩需要的方法就好。

内容的提问来源于stack exchange,提问作者Ryan S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:33:44