You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用JUnit5覆盖IOException捕获分支的代码测试

解决方案

方法1:传入无效的Zip字节数据(无需修改业务代码)

直接构造不符合Zip格式的字节数组,JDK原生的ZipInputStream在解析这类数据时会自动抛出IOException,刚好能覆盖catch分支,完全贴合真实异常场景。

测试代码示例(JUnit5):

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

class ServiceToTestTest {

    @Test
    void unzip_shouldCatchIOException_whenInvalidZipData() {
        ServiceToTest service = new ServiceToTest();
        // 传入一段非Zip格式的随机字节
        byte[] invalidZip = new byte[]{0x00, 0x01, 0x02, 0x03};
        // 执行方法,无未捕获异常说明catch分支生效
        assertDoesNotThrow(() -> service.unzip(invalidZip));
        // 若catch内有自定义逻辑,可在此添加对应断言(比如验证日志、状态变更等)
    }
}

方法2:重构代码解耦依赖(适合复杂测试场景)

如果需要灵活控制异常触发时机(比如在read阶段抛异常而非初始化阶段),可以把ZipInputStream的创建逻辑抽成可注入的工厂类,用Mockito mock工厂返回异常流。

重构后的业务代码

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.io.ByteArrayOutputStream;

public class ServiceToTest {
    // 注入Zip流工厂,默认使用实现类
    private final ZipStreamFactory zipStreamFactory;

    // 无参构造,兼容原有调用逻辑
    public ServiceToTest() {
        this.zipStreamFactory = new DefaultZipStreamFactory();
    }

    // 带参构造,用于测试注入mock实例
    public ServiceToTest(ZipStreamFactory zipStreamFactory) {
        this.zipStreamFactory = zipStreamFactory;
    }

    public void unzip(byte[] zipFile) {
        try (ZipInputStream zipInputStream = zipStreamFactory.createZipStream(new ByteArrayInputStream(zipFile))) {
            ZipEntry entry;
            while ((entry = zipInputStream.getNextEntry()) != null) {
                byte[] buffer = new byte[1024];
                int len;
                try (var file = new ByteArrayOutputStream(buffer.length)) {
                    while ((len = zipInputStream.read(buffer)) > 0) {
                        file.write(buffer, 0, len);
                    }
                    System.out.println(entry.getName());
                }
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
            // some logic or rethrow the exception
        }
    }

    // 定义Zip流工厂接口
    public interface ZipStreamFactory {
        ZipInputStream createZipStream(InputStream inputStream) throws IOException;
    }

    // 默认实现类,保持原有逻辑
    static class DefaultZipStreamFactory implements ZipStreamFactory {
        @Override
        public ZipInputStream createZipStream(InputStream inputStream) throws IOException {
            return new ZipInputStream(inputStream);
        }
    }
}

对应的测试代码(Mockito + JUnit5)

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipInputStream;
import static org.mockito.Mockito.*;

class ServiceToTestTest {

    @Test
    void unzip_shouldCatchIOException_whenZipStreamThrows() throws IOException {
        // mock工厂和ZipInputStream实例
        ServiceToTest.ZipStreamFactory mockFactory = Mockito.mock(ServiceToTest.ZipStreamFactory.class);
        ZipInputStream mockZipStream = Mockito.mock(ZipInputStream.class);

        // 配置工厂返回mock的Zip流
        when(mockFactory.createZipStream(any(InputStream.class))).thenReturn(mockZipStream);
        // 模拟调用getNextEntry时抛出IOException
        when(mockZipStream.getNextEntry()).thenThrow(new IOException("Test IO Exception"));

        ServiceToTest service = new ServiceToTest(mockFactory);
        service.unzip(new byte[0]);

        // 验证异常触发逻辑被执行
        verify(mockZipStream, times(1)).getNextEntry();
    }
}

为什么不推荐传null?

传null会触发NullPointerException,和需要覆盖的IOException不属于同一异常类型,且业务代码处理的是IO相关异常,用无效Zip数据更贴合真实业务场景,测试逻辑也更合理。

内容的提问来源于stack exchange,提问作者BugsOverflow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 05:20:32