使用PowerMock Mock父类protected方法后仍返回空指针问题求助
问题分析
在Bar.func()中调用了super.getUser(),该调用会直接执行父类Foo的getUser()方法,而非通过Bar实例的代理逻辑。你之前尝试mockbar.getUser()无效,核心原因是Bar并未重写该方法,super调用会绕过Bar实例的spy代理,直接执行父类的原始实现。
解决方案
以下两种方案无需修改业务代码即可解决问题:
方案1:针对父类类型mock方法
修改测试类,将Bar实例强转为Foo类型后mockgetUser(),同时确保@PrepareForTest包含父类Foo:
@RunWith(PowerMockRunner.class) @PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"}) @PrepareForTest({Bar.class, Foo.class}) // 新增Foo.class以支持父类方法mock public class BarTest { @Mock Mapper mapper; @Test public void testFunc() { Bar bar = PowerMockito.spy(new Bar()); // 使用ReflectionTestUtils注入mapper,替代直接赋值字段,更符合测试规范 ReflectionTestUtils.setField(bar, "mapper", mapper); // mock私有方法validateParams PowerMockito.doReturn(Result.success()).when(bar, "validateParams", any(), any()); // 初始化mockUser并设置info,避免后续调用getInfo()时NPE User mockUser = new User(); mockUser.setInfo("mock-info"); // 将bar强转为Foo类型,mock父类的getUser方法 PowerMockito.doReturn(mockUser).when((Foo) bar).getUser(); // mock mapper.mapTo方法,避免entity为null引发新的NPE Entity mockEntity = new Entity(); PowerMockito.when(mapper.mapTo(anyString(), eq(Entity.class))).thenReturn(mockEntity); bar.func("param1", "param2"); } }
方案2:使用PowerMock替换父类方法实现
如果方案1不生效,可尝试直接替换父类Foo中getUser()的方法逻辑:
@RunWith(PowerMockRunner.class) @PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"}) @PrepareForTest({Foo.class}) public class BarTest { @Mock Mapper mapper; @Test public void testFunc() throws Exception { Bar bar = new Bar(); ReflectionTestUtils.setField(bar, "mapper", mapper); // 获取父类Foo的getUser方法 Method getUserMethod = Foo.class.getDeclaredMethod("getUser"); // 替换该方法的实现,直接返回mockUser PowerMockito.replace(getUserMethod).with(new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { User mockUser = new User(); mockUser.setInfo("mock-info"); return mockUser; } }); // spy Bar实例以mock私有方法 PowerMockito.spy(bar); PowerMockito.doReturn(Result.success()).when(bar, "validateParams", any(), any()); // mock mapper.mapTo方法 PowerMockito.when(mapper.mapTo(anyString(), eq(Entity.class))).thenReturn(new Entity()); bar.func("param1", "param2"); } }
关键注意事项
@PrepareForTest必须包含父类Foo.class,否则PowerMock无法拦截父类方法的调用。- 务必mock
mapper.mapTo()方法,避免entity为null引发新的空指针异常。 - 使用
ReflectionTestUtils.setField()替代直接赋值字段,兼容私有/protected字段,更符合测试规范。
内容的提问来源于stack exchange,提问作者vurtne yuan
相关产品推荐
相关产品推荐

