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

Mockito抛出异常但JUnit无法捕获的问题排查

问题核心

你遇到的问题本质是:异常在FileDownloadThread子线程中抛出,JUnit的异常捕获机制只能监控主线程,无法感知子线程抛出的异常,所以无论用try-catch、@Test(expected)还是ExpectedException Rule都抓不到。

解决方案

1. 同步捕获子线程异常

用ExecutorService提交下载任务,通过Future.get()方法让子线程的异常传递到主线程,JUnit就能捕获:

@Test(expected = RuntimeException.class)
public void testDownloadFileWhenUrlNotFound() throws Exception {
    // 原有Mock逻辑:模拟URLConnection抛出FileNotFoundException
    URL mockUrl = mock(URL.class);
    URLConnection mockConn = mock(URLConnection.class);
    when(mockUrl.openConnection()).thenReturn(mockConn);
    when(mockConn.getInputStream()).thenThrow(new FileNotFoundException());

    // 用ExecutorService执行下载任务
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<?> future = executor.submit(() -> fileUpdater.downloadFile());
    
    // get()方法会抛出子线程中的异常
    future.get();
}

2. 抽离业务逻辑,单独测试

把FileDownloadThread里的业务代码(比如调用isUrlFileExists的逻辑)抽成独立方法,直接测试这个方法,避开线程干扰:

// 重构FileUpdater类,抽离业务逻辑
public class FileUpdater {
    public void downloadFile() {
        new FileDownloadThread(() -> checkUrlAndDownload()).start();
    }

    protected void checkUrlAndDownload() {
        if (!isUrlFileExists()) {
            throw new RuntimeException("文件不存在");
        }
        // 原有下载逻辑
    }

    private boolean isUrlFileExists() {
        // 原有URL连接检查逻辑
    }
}

// 测试类
@Test(expected = RuntimeException.class)
public void testCheckUrlWhenFileNotFound() {
    FileUpdater updater = spy(new FileUpdater());
    // Mock业务方法抛出异常
    doThrow(new RuntimeException()).when(updater).checkUrlAndDownload();
    
    // 直接调用业务方法,主线程可捕获异常
    updater.checkUrlAndDownload();
}

3. Mockito 1.6的URL处理注意事项

Mockito 1.6版本较老,Mock URL时要确保URLStreamHandlerFactory注册生效,避免真实URL逻辑干扰:

@Before
public void setUp() {
    URL.setURLStreamHandlerFactory(protocol -> new URLStreamHandler() {
        @Override
        protected URLConnection openConnection(URL u) throws IOException {
            return mock(URLConnection.class);
        }
    });
}
关键提醒
  • JUnit只处理主线程异常,子线程异常必须通过同步手段(如Future)传递到主线程
  • 单元测试优先聚焦业务逻辑,而非线程调度,抽离逻辑能让测试更简洁可靠
  • Mockito 1.6对JDK类的Mock支持有限,尽量通过依赖注入解耦,减少直接Mock URL这类复杂类的操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 04:25:21