JUnit测试中如何比较两个ByteArrayInputStream?含报错问题
如何在JUnit中正确比较两个ByteArrayInputStream?
首先得说,你当前的报错完全是因为用错了比较方式——直接调用ByteArrayInputStream.toString()来比较,这个方法默认返回的是对象的内存标识(类名@哈希码),你看到的43195e57和333291e3就是两个不同对象的哈希值,所以JUnit肯定会判定不相等。而且你的代码里还有几个隐藏的坑,我一步步给你理清楚:
先揪出代码里的致命错误
你这行代码完全搞错了文件读取的逻辑:
ByteArrayInputStream uploadByteArrayInputStream = new ByteArrayInputStream(file.toString().getBytes());
FileInputStream.toString()根本不是读取文件内容,它返回的是java.io.FileInputStream@xxxx这种对象标识字符串,你把这个字符串转成字节数组上传,相当于上传了一堆毫无意义的字节,而不是你要的图片文件!这是核心问题之一。
正确比较ByteArrayInputStream的方法
要比较两个流的内容,本质是比较它们包含的字节数组,有两种常用的靠谱方式:
方式1:转成字节数组后用assertArrayEquals比较
因为ByteArrayInputStream内部持有字节缓冲区,支持reset()方法重置指针,所以我们可以先把流的内容转成字节数组,再比较:
// 重置上传流的指针(因为putObject已经把流读到末尾了) uploadByteArrayInputStream.reset(); byte[] uploadBytes = IOUtils.toByteArray(uploadByteArrayInputStream); // 把从MinIO获取的流转成字节数组 byte[] downloadedBytes = IOUtils.toByteArray(stream); // 直接比较两个字节数组 assertArrayEquals(uploadBytes, downloadedBytes);
方式2:用Apache Commons IO的IOUtils.contentEquals直接比较流
如果你不想手动转数组,可以用IOUtils提供的工具方法,它会自动读取两个流的内容并逐字节比较:
// 重置上传流指针 uploadByteArrayInputStream.reset(); // 直接断言两个流内容相同 assertTrue(IOUtils.contentEquals(uploadByteArrayInputStream, stream));
⚠️ 注意:这个方法会把两个流都读到末尾,如果之后还要用流的话,需要重新获取或者提前保存内容。
给你修正后的完整测试代码
我把所有问题都修复了,包括文件读取、流的复用、资源自动关闭(用try-with-resources避免内存泄漏):
@Test public void fileIsSame() throws IOException, InvalidEndpointException, InvalidPortException, InvalidKeyException, InvalidBucketNameException, NoSuchAlgorithmException, InsufficientDataException, NoResponseException, ErrorResponseException, InternalException, InvalidArgumentException, XmlPullParserException { // try-with-resources自动关闭文件流,不用手动close try (FileInputStream file = new FileInputStream("/Users/gauris/Documents/samplephoto/pexels-photo-46710.jpeg")) { String fileName = "pexels-photo-46710.jpeg"; // 正确读取文件内容到字节数组 byte[] fileBytes = IOUtils.toByteArray(file); // 基于字节数组创建ByteArrayInputStream(可以多次reset复用) ByteArrayInputStream uploadByteArrayInputStream = new ByteArrayInputStream(fileBytes); // 上传到MinIO,这里直接用字节数组的长度,比available()更可靠 minioClient.putObject(bucketName, fileName, uploadByteArrayInputStream, fileBytes.length, "application/octet-stream"); // 重置上传流的指针,准备后续比较 uploadByteArrayInputStream.reset(); // 用try-with-resources自动关闭MinIO返回的流 try (InputStream stream = minioClient.getObject(bucketName, fileName)) { // 方法1:比较字节数组 byte[] downloadedBytes = IOUtils.toByteArray(stream); assertArrayEquals("上传和下载的文件内容不一致", fileBytes, downloadedBytes); // 如果你想用方法2,需要重新获取流(因为上面已经把stream读完了) // try (InputStream newStream = minioClient.getObject(bucketName, fileName)) { // assertTrue("上传和下载的文件内容不一致", IOUtils.contentEquals(uploadByteArrayInputStream, newStream)); // } } } }
最后再强调下关键要点
- 永远不要用
toString()比较流对象,这是在比较对象引用,不是内容; - 读取文件时,一定要用
IOUtils.toByteArray()或者手动读取字节数组,不要调用流的toString(); - 流一旦被读取到末尾,后续再读就拿不到内容了,要么提前保存字节数组,要么用
reset()(仅限支持重置的流,比如ByteArrayInputStream); - 用try-with-resources管理流资源,避免手动关闭遗漏导致的资源泄漏。
内容的提问来源于stack exchange,提问作者Gauri Singhal Singhal
相关产品推荐
相关产品推荐

