如何用PowerMockito调用Mock静态类的真实方法并修改参数?
解决PowerMockito替换静态方法参数并调用真实方法的问题
场景说明
无法修改被测类Foo,需使用PowerMockito调用其Mock后的真实静态方法whatever,同时将方法参数中的Callable<File>替换为自定义的TestFileCallable。
被测类Foo代码
public class Foo{ public static Bravo whatever(Tango tango, Callable<File> callable, Function<File, File> func, String golf){ callable.call(); // 希望调用TestFileCallable.call() } }
原测试类TestFoo代码(含问题)
@RunWith(PowerMockRunner.class) @PrepareForTest({Foo.class}) // 修正原拼写错误:PrepareFortest → PrepareForTest @PowerMockIgnore("javax.management.*") // 修正原语法错误:补充闭合引号 public class TestFoo{ public void testWhatever(){ PowerMockito.mockStatic(Foo.class); PowerMockito.when(Foo.whatever(Mockito.any(Tango.class), Matchers.any(), Matchers.any(), Mockito.anyString())) .thenAnswer(new Answer<Object>(){ @Override public Object answer(InvocationOnMock invocation) throws Throwable { Object[] args = invocation.getArguments(); Tango tango = (Tango) args[0]; Callable<File> callable = new TestFileCallable(); Function<File, File> func = (Function<File, File>) args[2]; String golf = (String) args[3]; // 至此步骤正常 Object result = invocation.callRealMethod(); // 问题:此方法会使用原参数调用,无法传入修改后的参数 return result; } }); } class TestFileCallable implements Callable<File>{ @Override public File call() throws Exception{ return Mockito.mock(File.class); } } }
解决方案
不能使用invocation.callRealMethod()(它会沿用原参数调用),需通过PowerMockito的Whitebox工具类直接反射调用目标类的真实静态方法,传入修改后的参数数组:
修改后的TestFoo关键代码
@RunWith(PowerMockRunner.class) @PrepareForTest({Foo.class}) @PowerMockIgnore("javax.management.*") public class TestFoo{ public void testWhatever(){ PowerMockito.mockStatic(Foo.class); PowerMockito.when(Foo.whatever(Mockito.any(Tango.class), Matchers.any(), Matchers.any(), Mockito.anyString())) .thenAnswer(new Answer<Object>(){ @Override public Object answer(InvocationOnMock invocation) throws Throwable { // 提取原参数并替换Callable Tango tango = (Tango) invocation.getArguments()[0]; Callable<File> callable = new TestFileCallable(); Function<File, File> func = (Function<File, File>) invocation.getArguments()[2]; String golf = (String) invocation.getArguments()[3]; // 构建修改后的参数数组,确保顺序、类型与目标方法完全匹配 Object[] modifiedArgs = new Object[]{tango, callable, func, golf}; // 直接调用Foo类的真实静态方法,传入新参数 Bravo result = Whitebox.invokeMethod(Foo.class, "whatever", modifiedArgs); return result; } }); } class TestFileCallable implements Callable<File>{ @Override public File call() throws Exception{ return Mockito.mock(File.class); } } }
核心说明
Whitebox.invokeMethod()可以绕过Mock代理,直接触发目标类的真实方法逻辑- 构建新参数数组时,必须严格对应目标方法的参数顺序与类型,避免反射调用失败
- 此方案无需修改被测类
Foo,完全通过测试代码实现参数替换需求
内容的提问来源于stack exchange,提问作者oitathi
相关产品推荐
相关产品推荐

