不使用PowerMockito时如何Mock被测类中的静态方法
问题分析与解决方案
核心问题
你的测试代码无效的原因是:静态变量MY_STATIC_BOOL在类加载阶段就已经通过调用真实的getYourStaticBool()完成赋值,而你在@BeforeAll中创建的MockedStatic是在类加载之后才生效的,根本无法拦截类加载时的方法调用。
可行解决方案(无需PowerMockito)
方案1:直接通过反射修改静态变量值
既然目标是让MY_STATIC_BOOL为true,跳过Mock静态方法的环节,直接用反射修改变量值是最直接的方式:
@ExtendWith(MockitoExtension.class) public class MyClassTest { private MyClass myClass = new MyClass(); @Test void shouldDoSth() throws NoSuchFieldException, IllegalAccessException { // 反射获取私有静态变量 Field staticBoolField = MyClass.class.getDeclaredField("MY_STATIC_BOOL"); staticBoolField.setAccessible(true); // 修改变量值为true staticBoolField.set(null, true); myClass.doSomething(); // 这里添加你的断言逻辑 } }
方案2:修改原代码实现懒加载(若允许修改业务代码)
如果可以调整MyClass的实现,把静态变量的初始化改为懒加载,就能让Mock逻辑生效:
public class MyClass { private static Boolean MY_STATIC_BOOL; // 改为包装类型,允许null public void doSomething() { if (getMyStaticBool()) { // 调用懒加载方法 // 业务逻辑 } } private static boolean getMyStaticBool() { if (MY_STATIC_BOOL == null) { MY_STATIC_BOOL = getYourStaticBool(); } return MY_STATIC_BOOL; } protected static boolean getYourStaticBool() { return Optional.ofNullable(System.getenv("foo")) .map(Boolean::parseBoolean) .orElse(false); } }
对应的测试代码调整为:
@ExtendWith(MockitoExtension.class) public class MyClassTest { private MyClass myClass = new MyClass(); @Test void shouldDoSth() { try (MockedStatic<MyClass> mockedMyClass = Mockito.mockStatic(MyClass.class)) { mockedMyClass.when(MyClass::getYourStaticBool).thenReturn(true); myClass.doSomething(); // 此时才会触发懒加载,调用Mock后的方法 // 断言逻辑 } } }
关于Spy的疑问
Mockito的spy用于部分Mock实例方法,针对静态方法的Spy需要通过Mockito.mockStatic(MyClass.class, Mockito.CALLS_REAL_METHODS)实现,但这依然解决不了类加载阶段静态变量已初始化的问题——因为MY_STATIC_BOOL的值在Spy创建前就已经固定了,所以Spy对你的场景没有帮助。
内容的提问来源于stack exchange,提问作者LancerX
相关产品推荐
相关产品推荐

