使用Mockito测试时出现ExceptionInInitializerError,如何忽略类的静态字段初始化?
你遇到的ExceptionInInitializerError是因为JVM首次加载StringTools类时,会先初始化所有静态字段,此时会调用Activator.getNumberOfDays(),而单测环境下没有Activator的运行环境,所以初始化失败抛出错误。普通Mockito mock静态类时默认会触发类加载,所以无法绕过这个逻辑,以下是可行的实现方案:
方案1:使用PowerMock直接抑制静态初始化
PowerMock原生支持跳过指定类的静态初始化逻辑,是最直接的适配方案:
- 单测类添加如下注解:
@RunWith(PowerMockRunner.class) // 填写StringTools的全限定类名 @SuppressStaticInitializationFor("com.xxx.xxx.StringTools") public class UtilsTest { }
- 正常mock
getCurrentName()静态方法即可,不会触发_numberOfDays的初始化逻辑。
方案2:使用高版本Mockito(3.4+)的静态Mock参数绕过
Mockito 3.4及以上版本提供了是否触发静态初始化的配置项,无需引入PowerMock:
@Test public void testConcatString() { // 配置mock时不触发静态初始化 try (MockedStatic<StringTools> mockedStatic = Mockito.mockStatic( StringTools.class, Mockito.withSettings().invokeStaticInitializers(false) )) { // 配置getCurrentName的mock返回值 mockedStatic.when(StringTools::getCurrentName).thenReturn("mockName"); // 执行测试 String result = Utils.concatString("test"); // 校验结果 Assert.assertEquals("testmockName", result); } }
方案3:业务代码优化(推荐)
从代码设计层面调整,避免无关逻辑耦合,后续所有场景都不会出现类似问题:
将需要依赖运行环境的静态字段改为懒加载,只有被使用时才触发初始化:
public class StringTools{ // 静态内部类只有被访问时才会加载初始化 private static class DaysHolder { private static final int _numberOfDays = Activator.getNumberOfDays(); } public static String getCurrentName(){ // 只要该方法没有用到DaysHolder._numberOfDays,就不会触发初始化 ... } // 只有用到_numberOfDays的方法才会触发初始化 public static int getDays() { return DaysHolder._numberOfDays; } }
调整后无需任何测试框架hack,直接mock静态方法即可正常运行。
内容的提问来源于stack exchange,提问作者Frederic
相关产品推荐
相关产品推荐

