如何Mock DataInputStream.read方法测试分段读大对象的循环逻辑?
问题根因
你的实现存在3个核心错误:
doReturn中的stream.read(xxx)会在测试代码执行阶段立即执行,而非mock被业务代码调用时才触发,且DataInputStream不存在read(int)签名的方法,入参类型不匹配会直接触发异常。- mock的
read(byte[] buffer)方法默认不会自动将测试数据写入传入的buffer参数,就算返回了正确的读取字节数,业务代码拿到的buffer也是空值,会出现逻辑错误。 - 你已经直接将mockStream作为参数传入
myMethod,whenNew的配置属于冗余代码,没有实际作用。
可行解决方案
方案1:通过Mockito Answer自定义read行为
如果你希望使用mock框架实现,可以通过Answer接口自定义read方法的逻辑,同时处理返回值和buffer写入:
@RunWith(MockitoJUnitRunner.class) public class MyTestClass { @Test public void myTestMethod() throws IOException { int objectLength = 1024; byte[] testData = BytesDecoderSpec.generateRandomString(objectLength).getBytes(StandardCharsets.UTF_8); DataInputStream mockStream = Mockito.mock(DataInputStream.class); int firstReadLen = testData.length / 2; Mockito.when(mockStream.read(Mockito.any(byte[].class))) // 第一次调用返回一半长度 .thenAnswer(invocation -> { byte[] buffer = invocation.getArgument(0); System.arraycopy(testData, 0, buffer, 0, firstReadLen); return firstReadLen; }) // 第二次调用返回剩余长度 .thenAnswer(invocation -> { byte[] buffer = invocation.getArgument(0); int remainLen = testData.length - firstReadLen; System.arraycopy(testData, firstReadLen, buffer, 0, remainLen); return remainLen; }) // 后续调用返回-1标记流结束 .thenReturn(-1); MyRealClass realObject = new MyRealClass(); ResultObject result = realObject.myMethod(mockStream, objectLength); // 补充断言逻辑验证结果正确性 } }
方案2:自定义分段输入流(更推荐,无mock框架依赖)
直接实现一个自定义InputStream,控制每次read的最大返回长度,完全规避mock框架的各类问题:
// 自定义分段输入流,限制单次读取的最大字节数 public class FragmentedByteArrayInputStream extends ByteArrayInputStream { private final int maxReadPerTime; public FragmentedByteArrayInputStream(byte[] buf, int maxReadPerTime) { super(buf); this.maxReadPerTime = maxReadPerTime; } @Override public int read(byte[] b, int off, int len) throws IOException { int actualReadLen = Math.min(len, maxReadPerTime); return super.read(b, off, actualReadLen); } }
测试代码直接使用该流即可:
@Test public void myTestMethod() throws IOException { int objectLength = 1024; byte[] testData = BytesDecoderSpec.generateRandomString(objectLength).getBytes(StandardCharsets.UTF_8); // 配置单次最多读取512字节,模拟大文件分段读取场景 FragmentedByteArrayInputStream bis = new FragmentedByteArrayInputStream(testData, 512); DataInputStream stream = new DataInputStream(bis); MyRealClass realObject = new MyRealClass(); ResultObject result = realObject.myMethod(stream, objectLength); // 补充断言逻辑验证结果正确性 }
内容的提问来源于stack exchange,提问作者user17331277
相关产品推荐
相关产品推荐

