Mockito中Mock方法返回空指针异常该如何解决?
嘿,我来帮你搞定这个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

