Mockito 2中静态方法打桩抛出InvalidUseOfMatchersException异常
嘿,我之前帮朋友排查过几乎一模一样的升级问题,咱们来一步步拆解这个InvalidUseOfMatchersException的根源和解决办法~
PowerMock 2.x 配合 Mockito 2.x 对参数匹配器的使用规则比旧版本(1.6.2+1.10.19)严格太多了,尤其是在处理静态方法的抑制/Stub场景时,旧版本允许的“混合具体参数和匹配器”的写法,在新环境下直接触发了Mockito的参数匹配器合法性检测。另外,PowerMock 2 Beta版本身可能存在一些兼容性bug,和你用的Mockito 2.16.1也可能存在版本适配问题。
1. 修正静态方法抑制的参数写法
这是最常见的触发点——如果你之前的抑制代码混合了具体值和参数匹配器,比如:
// 错误示例:混合了具体值"test"和匹配器anyInt() PowerMockito.suppress(PowerMockito.method(StaticUtils.class, "staticMethod", "test", anyInt()));
新环境下要求要么全用具体值,要么全用匹配器包装,正确写法二选一:
- 匹配特定值:用
eq()包装每个参数
PowerMockito.suppress(PowerMockito.method(StaticUtils.class, "staticMethod", eq("test"), eq(123)));
- 匹配任意值:全用Mockito的参数匹配器
PowerMockito.suppress(PowerMockito.method(StaticUtils.class, "staticMethod", anyString(), anyInt()));
2. 升级到稳定兼容的版本组合
你用的PowerMock 2 Beta版稳定性不足,建议换成PowerMock 2.x稳定版(比如2.0.9),同时确保Mockito版本在PowerMock官方兼容列表内——比如PowerMock 2.0.9适配Mockito 2.23.4及以上版本,你当前的2.16.1略旧,升级后能规避很多兼容性bug。
3. 调整测试类的注解配置
Java 10环境下,PowerMock需要额外配置@PowerMockIgnore来规避JDK模块系统的限制,同时确保注解配置符合PowerMock 2.x的规范:
@RunWith(PowerMockRunner.class) // 忽略JDK内部反射及XML相关模块,避免Java 10下的类加载异常 @PowerMockIgnore({"jdk.internal.reflect.*", "com.sun.org.apache.xerces.*", "javax.xml.*"}) // 必须标注需要处理的静态类 @PrepareForTest(StaticUtils.class) public class MyMockitoTest { // 你的测试代码 }
如果是用JUnit 5,还要换成PowerMockExtension替代PowerMockRunner,不过你提到编译用Java8,大概率还是JUnit4,上面的配置就够用。
4. 统一使用PowerMock的API操作静态类
不要混合Mockito和PowerMock的API来处理静态方法,比如不要用Mockito.when搭配PowerMockito.mockStatic,统一用PowerMock的API:
// 正确写法:全用PowerMock API PowerMockito.mockStatic(StaticUtils.class); PowerMockito.when(StaticUtils.staticMethod(anyString())).thenReturn("mockResult");
先写一个极简测试用例验证修复效果,排除其他干扰:
import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.mockito.ArgumentMatchers.anyString; @RunWith(PowerMockRunner.class) @PowerMockIgnore({"jdk.internal.reflect.*"}) @PrepareForTest(StaticUtils.class) public class StaticMethodSuppressTest { @Test public void testSuppressStaticMethod() { // 抑制静态方法 PowerMockito.suppress(PowerMockito.method(StaticUtils.class, "doSomething", anyString())); // 调用静态方法,不会执行原逻辑(原方法会抛异常,抑制后不会) StaticUtils.doSomething("test"); } } // 测试用的静态工具类 class StaticUtils { public static void doSomething(String param) { throw new RuntimeException("原方法执行了!应该被抑制!"); } }
如果这个极简用例能正常跑通,再逐步迁移你的原有测试代码,排查哪个部分的写法不符合新规范。
内容的提问来源于stack exchange,提问作者rainbowgoblin

