求助:如何覆盖公共方法中CompletableFuture的exceptionally分支?
如何覆盖CompletableFuture的exceptionally分支
第一步:修正原代码的致命错误
原代码里exceptionally分支调用aFuture.get()是逻辑错误——aFuture就是当前正在执行的CompletableFuture实例,此时它处于未完成状态,调用get()会导致无限阻塞。必须改为调用第二个Future实例aFuture1.get():
CompletableFuture<Optional<A>> aFuture = CompletableFuture.supplyAsync(() -> Optional.ofNullable(service.getA("As"))) .exceptionally((ex) -> { log.error("Exception Happen Fetching from another source"); CompletableFuture<Optional<A>> aFuture1 = CompletableFuture.supplyAsync(() -> Optional.ofNullable(service.getAAsB("As"))) .exceptionally((ex2) -> { log.error("Exception Happen Fetching from another source also failed"); return Optional.empty(); }); try { // 修正:调用aFuture1.get()而非aFuture.get() return aFuture1.get(); } catch(Exception exa) { throw new RuntimeException(exa); } });
第二步:编写测试用例覆盖分支
覆盖第一个exceptionally分支(首次调用失败)
用Mock框架(如Mockito)模拟service.getA("As")抛出异常,同时让getAAsB返回正常结果:
// 初始化Mock Service service = Mockito.mock(Service.class); // 让第一次调用抛出异常 Mockito.when(service.getA("As")).thenThrow(new RuntimeException("测试异常")); // 让备用调用返回有效实例 Mockito.when(service.getAAsB("As")).thenReturn(new A()); // 执行目标逻辑 CompletableFuture<Optional<A>> future = 你的测试类.目标方法(service); Optional<A> result = future.join(); // 验证逻辑触发 Assert.assertTrue(result.isPresent()); Mockito.verify(service).getA("As"); Mockito.verify(service).getAAsB("As");
覆盖第二个exceptionally分支(两次调用都失败)
同时模拟两次调用都抛出异常:
Service service = Mockito.mock(Service.class); Mockito.when(service.getA("As")).thenThrow(new RuntimeException("第一次调用异常")); Mockito.when(service.getAAsB("As")).thenThrow(new RuntimeException("备用调用异常")); CompletableFuture<Optional<A>> future = 你的测试类.目标方法(service); Optional<A> result = future.join(); // 验证结果为空,且两次调用都被触发 Assert.assertTrue(result.isEmpty()); Mockito.verify(service).getA("As"); Mockito.verify(service).getAAsB("As");
额外提示
- 测试时优先用
CompletableFuture.join()替代get(),无需处理受检异常,简化代码。 - 如果测试中Future持续阻塞,检查是否存在循环等待的逻辑错误(比如原代码的
aFuture.get()问题)。
内容的提问来源于stack exchange,提问作者vishvas chauhan
相关产品推荐
相关产品推荐

