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
相关产品推荐
相关产品推荐

