使用PowerMock+Mockito模拟静态方法触发InvalidUseOfMatchersException问题
解决PowerMock+Mockito静态方法Mock时的InvalidUseOfMatchersException问题
嘿,我来帮你搞定这个头疼的匹配器异常问题!咱们一步步拆解原因,再逐个解决:
1. 先把PowerMock的基础配置补全
要Mock静态方法,PowerMock有几个硬性要求,缺了这些很容易触发奇怪的匹配器错误:
- 你的测试类必须加上
@RunWith(PowerMockRunner.class)注解,告诉JUnit用PowerMock的运行器来执行测试 - 得加
@PrepareForTest({RSAHelper.class, AppHelper.class, LibUtil.class})注解——因为这些类里的静态方法都被你用到了,PowerMock需要提前修改它们的字节码才能Mock - 在测试方法的开头,一定要先调用
PowerMockito.mockStatic(RSAHelper.class),开启对这个类静态方法的Mock支持
2. 核心问题:byte数组的匹配方式错了
你用eq(Base64.decode(GOOD_ENCRYPTION_STRING, Base64.DEFAULT))来匹配第三个参数,但Mockito的eq()对数组是比引用不是比内容!也就是说,哪怕两个byte数组里的内容完全一样,只要是不同的对象,eq()就会认为不匹配,这不仅会导致Mock不生效,还可能触发匹配器异常。
解决这个问题的办法是用ArgumentMatchers.argThat()来自定义内容匹配:
// 先提前解码好预期的byte数组 byte[] expectedBytes = Base64.decode(GOOD_ENCRYPTION_STRING, Base64.DEFAULT); // 用argThat来检查数组内容是否相等 PowerMockito.when(RSAHelper.RSADecrypt( any(), any(), argThat(bytes -> Arrays.equals(bytes, expectedBytes)) )).thenReturn(userData);
如果你的Mockito版本比较旧,也可以用matches()(不过这个方法已经过时了,还是优先用argThat)。
3. 再确认参数匹配的规则
虽然你现在的代码里都用了匹配器,但还是要提一句:Mockito有个严格规则——要么所有参数都用匹配器,要么全用具体值,不能混着来。比如如果你写了when(RSAHelper.RSADecrypt(any(), "testKey", eq(...))),这里第二个参数是具体字符串,其他是匹配器,肯定会报错。你的代码里用了any()、any()、argThat(),都是匹配器,这部分是对的,不用改。
给你一个完整的示例代码参考
我把正确的测试结构写出来,你可以对照着调整自己的代码:
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatchers; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import android.content.Context; import java.util.Arrays; import android.util.Base64; @RunWith(PowerMockRunner.class) @PrepareForTest({RSAHelper.class, AppHelper.class, LibUtil.class}) public class YourTestClass { @Test public void testDecryptionFunction() { // 1. 初始化静态类的Mock PowerMockito.mockStatic(RSAHelper.class); PowerMockito.mockStatic(AppHelper.class); PowerMockito.mockStatic(LibUtil.class); // 2. 准备测试数据 String GOOD_ENCRYPTION_STRING = "your_encrypted_test_data"; byte[] expectedDecodedBytes = Base64.decode(GOOD_ENCRYPTION_STRING, Base64.DEFAULT); UserData userData = new UserData(); // 替换成你的实际返回对象 // 3. 先Mock依赖的其他静态方法 PowerMockito.when(AppHelper.getApplicationContext()).thenReturn(PowerMockito.mock(Context.class)); PowerMockito.when(LibUtil.getDecryptionKeyName()).thenReturn("test_decryption_key"); // 4. 正确Mock目标静态方法 PowerMockito.when(RSAHelper.RSADecrypt( ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.argThat(bytes -> Arrays.equals(bytes, expectedDecodedBytes)) )).thenReturn(userData); // 5. 执行你要测试的方法 // YourClassUnderTest testedObject = new YourClassUnderTest(); // testedObject.yourMethodToTest(); // 6. 可选:验证静态方法是否被正确调用 PowerMockito.verifyStatic(RSAHelper.class); RSAHelper.RSADecrypt( ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.argThat(bytes -> Arrays.equals(bytes, expectedDecodedBytes)) ); } }
最后再检查两个小细节
- 确保你用的是
PowerMockito.when()而不是普通Mockito的when()——静态方法的Mock必须用PowerMock的方法 - 确认
GOOD_ENCRYPTION_STRING解码后的内容和实际测试中传入的encryptedData解码后的内容完全一致,不然Mock还是不会生效(不过这不会触发匹配器异常,只是没效果)
内容的提问来源于stack exchange,提问作者Chen Adam
相关产品推荐
相关产品推荐

