如何从另一个线程触发JUnit测试用例失败
问题根因
- JUnit 仅会监听测试主线程的异常来判定测试用例是否通过,子线程抛出的未捕获异常只会打印到控制台,不会传导到测试主线程,因此主线程执行完
latch.await()后正常退出,测试就会被判定为通过。 - 自定义
UncaughtExceptionHandler不生效的核心原因是:默认Executors.newSingleThreadExecutor()使用的默认线程工厂没有绑定你定义的异常处理器,子线程抛出异常后只会触发默认的打印堆栈逻辑,不会触发你自定义的异常处理动作。
解决方案
方案1:使用submit()提交任务,通过Future获取子线程异常(最简便)
把execute()换成submit(),会返回Future对象,调用get()方法时子线程的异常会封装为ExecutionException抛到主线程,JUnit就可以捕获到该异常判定测试失败。
@Test public void test() throws InterruptedException, ExecutionException { var latch = new CountDownLatch(1); Future<?> future = Executors.newSingleThreadExecutor().submit(() -> { latch.countDown(); Assert.fail("Doesn't fail the test"); }); latch.await(); // 调用get获取子线程执行结果,子线程异常会在此处抛出 future.get(); }
方案2:自定义线程工厂绑定UncaughtExceptionHandler
如果需要保留execute()的提交方式,可以自定义线程工厂,为池内所有线程绑定你定义的未捕获异常处理器,同时把异常传导到主线程:
@Test public void test() throws InterruptedException { var latch = new CountDownLatch(1); // 定义容器存储子线程异常 AtomicReference<Throwable> exceptionRef = new AtomicReference<>(); // 自定义线程工厂,绑定异常处理器 ThreadFactory threadFactory = r -> { Thread thread = new Thread(r); thread.setUncaughtExceptionHandler((t, e) -> exceptionRef.set(e)); return thread; }; Executors.newSingleThreadExecutor(threadFactory).execute(() -> { latch.countDown(); Assert.fail("Doesn't fail the test"); }); latch.await(); // 主线程检查是否有子线程异常,有就抛出 if (exceptionRef.get() != null) { Assert.fail(exceptionRef.get().getMessage()); } }
内容的提问来源于stack exchange,提问作者Nolequen
相关产品推荐
相关产品推荐

