如何使用Mockito成功Mock含静态代码块的Abc类?
如何Mock带有静态初始化块且会抛出异常的类(JUnit 4 + Mockito 4.8.1)
问题场景
现有如下Abc类,其静态初始化块会调用可能抛出AbcException的静态方法fun():
class Abc{ static void fun() throws AbcException{ throw new Exception("Some exception message"); } static{ try{ fun(); }catch(AbcException ex){ ex.printStackTrace(); } } }
使用JUnit 4 + Mockito 4.8.1编写测试时,调用mockStatic(Abc.class)会触发类加载,进而执行静态初始化块,导致抛出AbcException,无法完成Mock。
解决方案
方案一:使用PowerMock拦截静态初始化逻辑
Mockito本身无法在类加载阶段拦截静态初始化块,PowerMock通过修改类字节码可以实现这一点,步骤如下:
- 引入PowerMock相关依赖(适配JUnit 4):
<!-- PowerMock JUnit 4 依赖 --> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency> - 在测试类上添加PowerMock注解:
@RunWith(PowerMockRunner.class) @PrepareForTest(Abc.class) public class AbcTest { // 测试代码 } - 在
@Before方法中抑制静态初始化块或目标方法:@Before public void setup() { // 抑制静态初始化块的执行 PowerMockito.suppress(PowerMockito.staticInitializer(Abc.class)); // 或者单独抑制fun()方法的执行 // PowerMockito.suppress(PowerMockito.method(Abc.class, "fun")); // 现在可以正常创建静态Mock try (MockedStatic<Abc> abcMock = Mockito.mockStatic(Abc.class)) { // 配置Mock行为,比如让fun()不抛出异常 abcMock.when(Abc::fun).doNothing(); } }
方案二:重构源码(推荐)
如果允许修改业务代码,建议将静态初始化块中的逻辑抽离为可控制的初始化方法,避免类加载时自动执行风险逻辑:
修改后的Abc类:
class Abc{ static void fun() throws AbcException{ // 原有业务逻辑 } // 手动初始化方法,替代静态初始化块 public static void init() { try{ fun(); }catch(AbcException ex){ ex.printStackTrace(); } } }
生产代码中在合适时机调用Abc.init()完成初始化,测试时可以先Mockfun()方法,再调用init(),避免类加载阶段抛出异常。
原因说明
Mockito的mockStatic方法需要先加载目标类,而JVM加载类时必然执行静态初始化块。此时fun()抛出异常会导致类加载失败,进而无法完成Mock。PowerMock通过字节码修改技术,在类加载时跳过静态初始化块的执行,从而解决这个问题。
内容的提问来源于stack exchange,提问作者Karthikeya H S
相关产品推荐
相关产品推荐

