JUnit测试Client类getObj方法:空指针错误排查求助
JUnit测试
getObj方法时的空指针问题排查与修复 你遇到的NullPointerException直接原因很明确——memoryCache对象没有被初始化或Mock,当getObj方法执行到memoryCache.getStatus(p.toString())时,这个对象是null,自然触发空指针。除此之外,你的测试代码还有几个细节问题需要修正,我一步步给你梳理:
一、核心问题拆解
- @Before方法的变量定义错误:你在
@Before方法里定义了private COSAPIClient myClient;这类变量,这会导致这些变量是方法局部变量,方法执行完就销毁了,测试方法里根本拿不到正确的实例。应该把这些变量声明为测试类的成员变量。 - 变量名不一致:比如你声明了
FileStatus myStatus;,但初始化的是myFileStatus = PowerMockito.mock(FileStatus.class);,这会导致myStatus始终为null,后续逻辑必然出错。 - 未Mock关键依赖:
memoryCache是getObj方法的核心依赖,你完全没有对它进行Mock或初始化,这是触发空指针的直接原因。 - Spy用法不当:你直接
spy(new Client(uri, conf)),但没有替换Client内部的memoryCache、getStatus等依赖,导致测试时还是调用真实的未初始化对象。
二、修复步骤与完整测试代码
首先,确保你的测试类添加PowerMock必要的注解(如果需要Mock私有方法、静态方法或者替换类内部依赖),然后按以下方式编写测试:
1. 测试类基础配置与成员变量
import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.mockito.Mock; import org.powermock.reflect.Whitebox; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @RunWith(PowerMockRunner.class) @PrepareForTest(Client.class) // 如果需要mock Client里的私有/静态方法,比如pathToKey public class ClientTest { // 被测类实例 private Client myClient; // Mock依赖对象 @Mock private MemoryCache memoryCache; // 假设你的memoryCache类型是MemoryCache @Mock private FileStatus myStatus; @Mock private AmazonS3 amazonS3Client; @Mock private InputStream myInputStream; @Mock private FSDataInputStream fsDataInputStream; // 测试用常量 private String hName = "xyz://aa-bb-cc/"; private Path p = new Path("cos://aa-bb-cc/data7-1-23-a.txt"); private String objectKey = "mock-key"; // 模拟pathToKey的返回值 private String bucket = "aa-bb-cc"; }
2. @Before初始化方法
@Before public void setUp() throws URISyntaxException { // 初始化被测Client实例 URI uri = new URI("xyz://aa-bb-cc/data7-1-23-a.txt"); Configuration conf = new Configuration(); myClient = PowerMockito.spy(new Client(uri, conf)); // 把Mock的memoryCache注入到Client实例中(假设Client里的memoryCache是私有成员) Whitebox.setInternalState(myClient, "memoryCache", memoryCache); // 模拟pathToKey方法的返回值(如果这个方法是Client的私有方法) PowerMockito.doReturn(objectKey).when(myClient, "pathToKey", hName, p); }
3. 场景1:memoryCache返回null时,调用getStatus()
@Test public void getObj_WhenMemoryCacheStatusIsNull_CallsGetStatus() throws IOException { // 1. 给定:memoryCache.getStatus返回null PowerMockito.when(memoryCache.getStatus(p.toString())).thenReturn(null); // 给定:getStatus方法返回非目录的FileStatus PowerMockito.when(myClient.getStatus(hName, p, "getObject")).thenReturn(myStatus); PowerMockito.when(myStatus.isDirectory()).thenReturn(false); // 给定:InputStream和FSDataInputStream的创建逻辑 PowerMockito.whenNew(InputStream.class).withArguments(bucket, objectKey, myStatus.getLen(), amazonS3Client, anyLong(), any(InputPolicy.class)) .thenReturn(myInputStream); PowerMockito.whenNew(FSDataInputStream.class).withArguments(myInputStream).thenReturn(fsDataInputStream); // 2. 执行 FSDataInputStream result = myClient.getObj(hName, p); // 3. 验证 PowerMockito.verify(myClient, PowerMockito.times(1)).getStatus(hName, p, "getObject"); assert result == fsDataInputStream; }
4. 场景2:status是目录时,抛出FileNotFoundException
@Test(expected = FileNotFoundException.class) public void getObj_WhenStatusIsDirectory_ThrowsFileNotFoundException() throws IOException { // 1. 给定:memoryCache.getStatus返回目录类型的FileStatus PowerMockito.when(memoryCache.getStatus(p.toString())).thenReturn(myStatus); PowerMockito.when(myStatus.isDirectory()).thenReturn(true); // 2. 执行:预期抛出异常 myClient.getObj(hName, p); }
三、关键注意事项
- 如果
pathToKey是私有方法,必须用PowerMockito.doReturn(...).when(myClient, "pathToKey", ...)来模拟返回值,否则会执行真实方法可能导致未知错误。 - 如果你不需要Mock构造方法(比如
InputStream的创建),可以不用@PrepareForTest,但如果要模拟new关键字创建对象,必须添加这个注解并指定对应的类。 - 确保所有依赖的Mock对象都被正确注入到被测类中,比如
memoryCache、client等,避免出现未初始化的情况。
内容的提问来源于stack exchange,提问作者pac
相关产品推荐
相关产品推荐

