使用PowerMock进行带参构造Mock时报ExceptionInInitializerError如何解决
java.lang.ExceptionInInitializerError触发在PowerMockito.mockStatic(MyCache.class)执行阶段,本质是PowerMock mock静态类时默认会执行该类的真实静态初始化逻辑,如果MyCache的静态代码块、静态属性初始化依赖外部资源(比如配置文件、数据库连接、其他未mock的类),就会触发初始化失败,可按以下步骤修复:
第一步:禁止相关类执行静态初始化代码
新增@SuppressStaticInitializationFor注解,值为MyCache的全限定类名(比如你的类在com.xxx.util包下就填"com.xxx.util.MyCache"),如果MyAlgorithm也有静态初始化逻辑导致报错,同样可以把它的全限定类名加到该注解的数组中。示例注解配置:@RunWith(PowerMockRunner.class) @PrepareForTest({MyCache.class, MyAlgorithm.class, 你业务代码里调用new MyAlgorithm的类.class}) @SuppressStaticInitializationFor("com.xxx.util.MyCache") // 替换成你MyCache的实际全类名 public class Test {第二步:修正
whenNew的匹配逻辑和配置
PowerMock的whenNew生效要求:调用构造方法的业务类必须加入@PrepareForTest列表,比如你要mock的那行代码写在SearchService类里,就必须把SearchService.class加到@PrepareForTest的数组中。
同时如果你的测试场景中keyword.trim()不一定等于"ABC",建议用参数匹配器放宽匹配规则:PowerMockito.whenNew(MyAlgorithm.class).withArguments(Mockito.anyString()).thenReturn(alg);第三步:调整mock的执行时机(可选,优化测试隔离)
建议把静态mock、构造方法mock的逻辑从@BeforeClass移到@Before注解的非静态方法中,避免多个测试用例之间的mock状态互相干扰。第四步:校验依赖版本兼容性
确认你引入的PowerMock、Mockito、JUnit4版本互相兼容,常见兼容组合参考:- JUnit 4.12 + Mockito 2.8.9 + PowerMock 1.7.4
- JUnit 4.13 + Mockito 3.x + PowerMock 2.x
修改后完整示例代码
@RunWith(PowerMockRunner.class) // 替换SearchService为你实际写了MySearch mySearch = MyCache.getData(...)这行代码的业务类 @PrepareForTest({MyCache.class, MyAlgorithm.class, SearchService.class}) @SuppressStaticInitializationFor("com.xxx.util.MyCache") // 替换为MyCache实际全类名 public class Test { @Before public void setUp() throws Exception { PowerMockito.mockStatic(MyCache.class); MyAlgorithm alg = Mockito.mock(MyAlgorithm.class); // 可根据测试需求替换为精确参数匹配 PowerMockito.whenNew(MyAlgorithm.class).withArguments(Mockito.anyString()).thenReturn(alg); MySearch mySearch = Mockito.mock(MySearch.class); PowerMockito.when(MyCache.getData(alg, MySearch.class)).thenReturn(mySearch); } // 你的测试用例 @Test public void testSearchLogic() { // 执行业务逻辑、断言结果 } }
内容的提问来源于stack exchange,提问作者Pamba

