使用Mockito.mockConstruction测试时被测类Logger为null如何解决
问题根因
你遇到的问题由两个核心错误导致:
- 静态变量初始化时机问题:
Utility类的log是静态成员,会在类第一次被加载时就完成初始化,早于你测试方法内的Mock逻辑执行,此时如果LoggerBean初始化失败,log就已经被赋值为null,后续再Mock也不会重新触发静态变量初始化。 - Mock逻辑不匹配:
- 你只Mock了
LoggerBean的构造方法,但Utility中是通过静态方法LoggerBean.getLoggerBean()获取LoggerBean实例,你并没有Mock这个静态方法的返回值,所以根本不会用到你Mock的构造生成的对象。 - 你Stub
getLogger方法时传入的参数是测试类UtilityTest.class,但Utility里调用getLogger传入的是Utility.class,Stub规则不匹配,自然返回默认的null。
- 你只Mock了
解决方案
推荐两种可行方案,按需选择:
方案1:直接反射修改静态log字段(最简便)
不需要复杂的Mock逻辑,直接通过反射给Utility的静态log字段赋值即可:
import java.lang.reflect.Field; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNotNull; class UtilityTest { @BeforeEach void initLog() throws NoSuchFieldException, IllegalAccessException { Logger testLog = Logger.getLogger(Utility.class); Field logField = Utility.class.getDeclaredField("log"); logField.setAccessible(true); // 静态字段赋值时第一个参数传null即可 logField.set(null, testLog); } @Test void testFromJson() throws Exception { String json = " {\"key\":\"k1\",\"value\":\"v1\"}"; assertNotNull(Utility.fromJson(json, Tuple.class)); } }
方案2:完整Mock静态方法+控制类加载顺序
如果需要严格走LoggerBean的获取流程,可以MockLoggerBean的静态工厂方法,且保证Mock逻辑在Utility类加载前执行:
import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.assertNotNull; class UtilityTest { @Test void testFromJson() throws Exception { // 先Mock LoggerBean的静态方法,此时需要保证Utility还未被加载 try (MockedStatic<LoggerBean> mockedStatic = mockStatic(LoggerBean.class)) { // 构造Mock的LoggerBean实例 LoggerBean mockBean = mock(LoggerBean.class); // 注意Stub参数要和Utility里调用的一致,使用Utility.class when(mockBean.getLogger(Utility.class)).thenReturn(Logger.getLogger(Utility.class)); // Stub静态工厂方法的返回值 mockedStatic.when(LoggerBean::getLoggerBean).thenReturn(mockBean); // 此时第一次加载Utility类,触发静态变量初始化,会拿到Mock的log实例 String json = " {\"key\":\"k1\",\"value\":\"v1\"}"; assertNotNull(Utility.fromJson(json, Tuple.class)); } } }
如果你的测试运行环境中Utility类已经在测试执行前被加载过,方案2需要配合反射重置log字段才能生效。
内容的提问来源于stack exchange,提问作者Ashish
相关产品推荐
相关产品推荐

