Java 8升级至21后Arquillian集成测试中Mockito.mock失效问题
问题背景
将Java版本从8升级到21后,使用远程Wildfly配合Arquillian做JUnit4集成测试时,测试类中调用Mockito.mock()方法抛出初始化异常:
java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.MockMaker (alternate: null)
at deployment.testarchive.war//org.mockito.internal.configuration.plugins.PluginLoader$1.invoke(PluginLoader.java:85)
...(省略部分栈追踪内容)
尝试过相关解决方案但因JUnit4+远程Wildfly环境不生效,移除测试类的@RunWith(Arquillian.class)后Mockito可正常运行,但集成测试无法执行。当前Arquillian的WAR部署代码如下:
@ArquillianSuiteDeployment public class Deployments { @Deployment public static WebArchive deploy(){ return ShrinkWrap.create(WebArchive.class,"testarchive.war") .addPackages(true,"at.felder") ...(省略部分配置代码) .addAsResource("org/apache/commons/vfs2/impl/providers.xml"); } }
解决方案
1. 对齐依赖版本兼容性
Java 21需要搭配Mockito 5.x及以上版本,同时确保Arquillian核心、远程Wildfly容器适配器的版本适配Java 21和JUnit4:
- Mockito选择
5.6.0或更高版本 - Arquillian核心使用
1.7.0.Final及以上版本 - Wildfly容器适配器选用对应Wildfly版本的适配包(如Wildfly 29+适配Java 21)
2. 从部署包中移除Mockito相关依赖
远程Wildfly环境中,Mockito是测试端工具,不需要被打包进部署到服务器的WAR中,否则会引发服务器类加载器与测试类加载器的冲突。修改部署代码,排除Mockito及其依赖:
@ArquillianSuiteDeployment public class Deployments { @Deployment public static WebArchive deploy(){ return ShrinkWrap.create(WebArchive.class,"testarchive.war") .addPackages(true, "at.felder") // 排除Mockito及依赖类,避免服务器端加载 .exclude("org.mockito.**") .exclude("net.bytebuddy.**") .exclude("org.objenesis.**") ...(省略部分配置代码) .addAsResource("org/apache/commons/vfs2/impl/providers.xml"); } }
同时在Maven/Gradle配置中,确保Mockito依赖的scope为test,不会被打包进WAR。
3. 使用Arquillian Mockito扩展管理Mock对象
引入Arquillian的Mockito扩展,它能在JUnit4+Arquillian环境中正确处理Mock的初始化,避免插件加载异常:
- 添加Maven依赖:
<dependency> <groupId>org.jboss.arquillian.extension</groupId> <artifactId>arquillian-mockito</artifactId> <version>1.1.0.Final</version> <scope>test</scope> </dependency>
- 在测试类中用
@Mock注解创建Mock,替代直接调用Mockito.mock():
@RunWith(Arquillian.class) public class YourIntegrationTest { @Mock private YourDependency mockDependency; // 被测服务由Arquillian注入 @Inject private YourService serviceUnderTest; @Before public void setup() { // 初始化Mock MockitoAnnotations.initMocks(this); // 配置Mock行为 when(mockDependency.someMethod()).thenReturn("expectedResult"); } @Test public void testServiceLogic() { serviceUnderTest.execute(); // 验证Mock调用 verify(mockDependency).someMethod(); } }
4. 排查类加载器配置
远程Wildfly环境下,测试客户端与服务器的类加载器相互隔离。确保测试运行时,Mockito的JAR只存在于测试类路径中,不会被部署到服务器。可以通过解压WAR包检查是否意外包含了Mockito相关文件。
内容的提问来源于stack exchange,提问作者MJCM

