如何Mock Properties.load()方法?解决测试中空指针异常问题
问题分析与解决方案
核心问题
- 静态方法无法被Mockito普通Mock:你的
loadProperties是静态方法,Mockito默认不支持Mock静态方法,测试里创建的PropertiesMock对象完全没被用到,实际调用的还是原方法里new出来的Properties实例。 - 资源流返回Null:
Foo.class.getClassLoader().getResourceAsStream("id")找不到指定资源,返回null,调用properties.load(null)直接抛出空指针异常。 - 代码语法错误:原
loadProperties方法的return语句位置错误,应放在方法块内;getSomething方法里的something变量未定义,会导致编译错误。
修复步骤
1. 修正Foo类的语法与基础逻辑
public class Foo { // 定义所需的变量,示例设为字符串常量 private static final String something = "target_key"; public A getSomething() { Properties properties = loadProperties().getProperty(something); // 补充返回逻辑,根据实际业务调整 return new A(); } public static Properties loadProperties() { Properties properties = new Properties(); try { InputStream inputStream = Foo.class.getClassLoader().getResourceAsStream("id"); if (inputStream != null) { properties.load(inputStream); } else { // 处理资源找不到的场景,避免后续空指针 throw new IOException("配置文件'id'未找到"); } } catch (IOException e) { e.printStackTrace(); } return properties; } }
2. 测试方案调整
针对静态方法的Mock需求,有两种可行方案:
方案一:使用Mockito-inline支持静态Mock
确保依赖中引入mockito-inline(Mockito 3.4+版本支持),修改测试代码如下:
import org.junit.Test; import org.mockito.Mockito; import java.util.Properties; public class FooTest { @InjectMocks Foo foo = new Foo(); @Test public void test() throws Exception { // Mock静态方法loadProperties try (Mockito.MockedStatic<Foo> mockedFoo = Mockito.mockStatic(Foo.class)) { Properties mockProps = Mockito.mock(Properties.class); // 指定静态方法返回Mock的Properties实例 mockedFoo.when(Foo::loadProperties).thenReturn(mockProps); // 按需Mock getProperty的返回值 Mockito.when(mockProps.getProperty("target_key")).thenReturn("test_value"); foo.getSomething(); // 验证静态方法是否被调用 mockedFoo.verify(Foo::loadProperties); } } }
方案二:重构代码,移除静态方法(更推荐的设计)
将配置加载逻辑抽成独立类,改为实例依赖,便于Mock:
// 独立的配置加载类 public class PropertyLoader { public Properties loadProperties() throws IOException { Properties properties = new Properties(); InputStream inputStream = getClass().getClassLoader().getResourceAsStream("id"); if (inputStream == null) { throw new IOException("配置文件'id'未找到"); } properties.load(inputStream); return properties; } } // 修改Foo类,通过构造方法注入依赖 public class Foo { private static final String something = "target_key"; private PropertyLoader propertyLoader; public Foo(PropertyLoader propertyLoader) { this.propertyLoader = propertyLoader; } public A getSomething() { try { Properties properties = propertyLoader.loadProperties().getProperty(something); return new A(); } catch (IOException e) { e.printStackTrace(); return null; } } }
对应的测试代码(无需处理静态方法,逻辑更简洁):
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.util.Properties; @RunWith(MockitoJUnitRunner.class) public class FooTest { @Mock PropertyLoader mockPropertyLoader; @InjectMocks Foo foo; @Test public void test() throws Exception { Properties mockProps = Mockito.mock(Properties.class); Mockito.when(mockPropertyLoader.loadProperties()).thenReturn(mockProps); Mockito.when(mockProps.getProperty("target_key")).thenReturn("test_value"); foo.getSomething(); // 验证依赖方法的调用情况 Mockito.verify(mockPropertyLoader).loadProperties(); Mockito.verify(mockProps).getProperty("target_key"); } }
3. 资源文件注意事项
确保id配置文件放在项目的classpath目录下(比如src/main/resources),这样getResourceAsStream才能正确读取到文件,避免返回null引发空指针。
内容的提问来源于stack exchange,提问作者user2374431
相关产品推荐
相关产品推荐

