You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mockito测试抛出java.lang.ExceptionInInitializerError问题求助

Mockito单元测试抛出java.lang.ExceptionInInitializerError异常排查与解决

异常堆栈信息

java.lang.ExceptionInInitializerError
    at org.mockito.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:167)
    at org.mockito.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:217)
    at org.mockito.cglib.core.KeyFactory$Generator.create(KeyFactory.java:145)
    at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:117)
    at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:109)
    at org.mockito.cglib.core.KeyFactory.create(KeyFactory.java:105)
    at org.mockito.cglib.proxy.Enhancer.<clinit>(Enhancer.java:70)
    at org.mockito.internal.creation.cglib.ClassImposterizer.createProxyClass(ClassImposterizer.java:95)
    at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:57)
    at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49)
    at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24)
    at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
    at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
    at org.mockito.Mockito.mock(Mockito.java:1285)
    at org.mockito.Mockito.mock(Mockito.java:1163)
    at com.in28minutes.business.TodoBusinessImplTest_withMock.testWithMock(TodoBusinessImplTest_withMock.java:20)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:577)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @685cb137
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:200)
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:194)
    at org.mockito.cglib.core.ReflectUtils$2.run(ReflectUtils.java:57)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:318)
    at org.mockito.cglib.core.ReflectUtils.<clinit>(ReflectUtils.java:47)
    ... 38 more

相关代码

TodoService.java

package com.in28minutes.data.api;

import java.util.List;

public interface TodoService {
    public List<String> retrieveTodos(String user);
}

TodoBusinessImpl.java

import java.util.ArrayList; 
import java.util.List;

import com.in28minutes.data.api.TodoService;

public class TodoBusinessImpl {
    private TodoService todoService;

    public TodoBusinessImpl(TodoService todoService) {
        this.todoService = todoService;
    }
    
    public List<String> retrieveTodosRelatedToSpring(String user){
        List<String> filteredTodos = new ArrayList<String>();
        List<String> alltodos = todoService.retrieveTodos(user);
        
        for(String todo : alltodos) {
            if(todo.contains("Spring")) {
                filteredTodos.add(todo);
            }
        }
        
        return filteredTodos;
    }
}

TodoBusinessImplTest_withMock.java

package com.in28minutes.business;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import com.in28minutes.data.api.TodoService;

public class TodoBusinessImplTest_withMock {

    @Test
    public void testWithMock() {
        
        TodoService todoServiceMock = mock(TodoService.class);
        
        List<String> todo = Arrays.asList("Learn Spring MVC", "Learn Spring", "Learn To Code");
        
        when(todoServiceMock.retrieveTodos("Dummy")).thenReturn(todo);
        
        TodoBusinessImpl todoBusinessImpl = new TodoBusinessImpl(todoServiceMock);
        
        List<String> filteredTodos = todoBusinessImpl.retrieveTodosRelatedToSpring("Dummy");
        
        assertEquals(2, filteredTodos.size());
        
    }

}

问题原因与解决方案

从堆栈的Caused by部分可以看出,核心问题是JDK 9+的模块系统阻止了老版本Mockito依赖的CGLIB框架进行反射访问:老版本Mockito用CGLIB尝试修改java.lang.ClassLoader的方法访问权限,但JDK 9+的模块系统不允许未命名模块访问java.base模块的内部API。

方案1:升级Mockito版本(推荐)

使用Mockito 3.0及以上版本,这些版本已适配JDK 9+模块系统,改用ByteBuddy生成代理类,彻底避免反射访问受限问题。

如果用Maven,更新依赖:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.11.0</version> <!-- 可替换为最新稳定版 -->
    <scope>test</scope>
</dependency>

如果用Gradle:

testImplementation 'org.mockito:mockito-core:4.11.0'

方案2:添加JVM启动参数(临时绕过)

若暂时无法升级Mockito,可在运行测试时添加JVM参数,允许未命名模块访问java.base的相关包:

--add-opens java.base/java.lang=ALL-UNNAMED

在Eclipse中设置方式:右键测试类 → Run As → Run Configurations → Arguments标签页,在VM arguments中添加上述参数。

注意:此方法仅为临时绕过限制,长期建议使用方案1升级Mockito版本。

内容的提问来源于stack exchange,提问作者d_hrishi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:07:03