升级至Java 17后Mockito模拟Executable报'Unsupported settings'错误的解决
解决Java 17下Mockito无法模拟java.lang.reflect.Executable的问题
问题根源
Java 9及以上引入的模块系统(JPMS)对java.base模块中的核心类(包括java.lang.reflect.Executable)施加了保护机制,Mockito默认的字节码操作方式(依赖CGLIB/ASM)无法修改这些受保护的核心类,因此直接调用mock(Executable.class)会抛出不支持的类型错误。而Java 8没有模块系统限制,所以之前的代码能正常运行。
可行解决方案
1. 改用实际子类的Spy对象(优先推荐简单场景)
Executable是抽象类,实际业务中它的子类是Method或Constructor。可以获取一个真实的子类实例,再用Mockito的spy来包装,既能模拟行为,又避开核心类的限制:
// 示例:获取一个真实的Method实例并创建Spy Method testMethod = YourTestClass.class.getDeclaredMethod("testMethod"); Executable executableSpy = spy(testMethod);
2. 引入Mockito-inline扩展(通用解决方案)
Mockito-inline模块采用ByteBuddy的inline字节码生成策略,支持模拟Java核心类。
- 依赖配置:
Maven:
Gradle:<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>4.0.0+</version> <!-- 选择兼容Java 17的版本,如4.11.0+ --> <scope>test</scope> </dependency>testImplementation 'org.mockito:mockito-inline:4.11.0' - 配置完成后,原代码可以直接正常运行:
Executable executable = mock(Executable.class);
3. 自定义Executable子类(特殊场景备用)
如果上述方案都不适用,可以手动实现Executable的子类,再模拟这个自定义类:
// 自定义Executable子类,实现所有抽象方法 class MockExecutable extends Executable { @Override public boolean isVarArgs() { return false; } @Override public boolean isSynthetic() { return false; } @Override public int getModifiers() { return 0; } @Override public String getName() { return "mockMethod"; } @Override public Class<?> getDeclaringClass() { return Object.class; } @Override public Class<?>[] getParameterTypes() { return new Class[0]; } @Override public Class<?>[] getExceptionTypes() { return new Class[0]; } // 实现剩余的抽象方法,根据测试需求返回对应值 } // 模拟自定义子类 Executable executable = mock(MockExecutable.class);
原代码的问题
原代码直接尝试模拟java.base模块中的核心抽象类Executable,在Java 17的模块系统保护下,Mockito默认的代理机制无法对这类核心类进行字节码增强,因此触发了不支持类型的错误。
内容的提问来源于stack exchange,提问作者mbilgil
相关产品推荐
相关产品推荐

