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

JUnit测试在CompletableFuture.allOf().join()处无限阻塞的解决方法

解决CompletableFuture.allOf().join()在JUnit测试中阻塞的问题

问题根源

你Mock了Executor但未让它实际执行提交的异步任务,导致future1和future2始终处于未完成状态,join()因此无限阻塞。以下是三种可行的测试实现方案:


方案1:使用同步执行的Executor

直接替换Mock的Executor为同步执行任务的实现,提交的Supplier会立刻在当前线程执行,Future快速完成,不会触发阻塞。

测试代码示例:

@ExtendWith(MockitoExtension.class)
class SampleTest {
    @InjectMocks
    private Sample sample;

    @Mock
    private SomeClass1 someClass1;
    @Mock
    private SomeClass someClass;
    @Mock
    private SomeClass2 someClass2;

    @BeforeEach
    void setUp() {
        // 创建同步Executor:提交任务时立即执行
        Executor syncExecutor = Runnable::run;
        // 给Sample的executor字段赋值
        ReflectionTestUtils.setField(sample, "executor", syncExecutor);
        
        // Mock依赖方法的返回值
        when(someClass1.someMethod()).thenReturn(new Obj1());
        when(someClass.someMethod(any(Obj1.class))).thenReturn(new Obj1());
        when(someClass2.someMethod()).thenReturn(new Obj2());
        when(someClass.someMethod(any(Obj2.class))).thenReturn(new Obj2());
    }

    @Test
    void testSampleMethod() {
        // 执行测试方法,无阻塞
        sample.SampleMethod(new Request());
        // 验证业务逻辑,比如someClass的方法调用次数
        verify(someClass, times(2)).someMethod(any());
    }
}

方案2:Mock Executor时手动触发任务执行

如果必须Mock Executor,可借助Mockito的Answer捕获提交的任务,手动执行以确保Future完成。

测试代码示例:

@ExtendWith(MockitoExtension.class)
class SampleTest {
    @InjectMocks
    private Sample sample;
    @Mock
    private Executor executor;
    @Mock
    private SomeClass1 someClass1;
    @Mock
    private SomeClass someClass;
    @Mock
    private SomeClass2 someClass2;

    @BeforeEach
    void setUp() {
        // Mock Executor的execute方法,手动执行提交的任务
        doAnswer(invocation -> {
            Runnable task = invocation.getArgument(0);
            task.run(); // 立即执行异步任务
            return null;
        }).when(executor).execute(any(Runnable.class));

        // Mock依赖方法返回值
        when(someClass1.someMethod()).thenReturn(new Obj1());
        when(someClass.someMethod(any(Obj1.class))).thenReturn(new Obj1());
        when(someClass2.someMethod()).thenReturn(new Obj2());
        when(someClass.someMethod(any(Obj2.class))).thenReturn(new Obj2());
    }

    @Test
    void testSampleMethod() {
        sample.SampleMethod(new Request());
        verify(someClass, times(2)).someMethod(any());
    }
}

方案3:强制完成CompletableFuture(特殊场景用)

如果无需测试异步执行逻辑,仅想跳过阻塞,可通过反射强制完成Future,但这种方式会破坏原有代码逻辑,仅适用于极端场景,不推荐常规使用。

额外提示

你的Sample类代码存在一处小错误:future2的SupplyAsync指定了Supplier<Obj1>,但实际应匹配返回值类型Obj2,建议修正以避免类型转换异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 08:45:30