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

使用Mockito测试CompletableFuture.supplyAsync时测试阻塞问题解决

解决Mockito测试CompletableFuture时无限阻塞的问题

你的测试之所以无限阻塞,核心原因是你创建的模拟CompletableFuture从未完成。在测试代码里,你实例化了userFuture和userEntityFuture,但没有调用complete()方法给它们设置返回值。当被测试的validateUserCounterparty方法执行到result.get()时,会一直等待Future的结果,导致测试永远无法结束。

解决方案

1. 让模拟的CompletableFuture处于已完成状态

不要手动创建空的CompletableFuture,而是直接用CompletableFuture.completedFuture()创建自带返回值的已完成Future,或者在创建空Future后主动调用complete()方法填充结果。

2. 完善测试依赖的模拟数据

需要模拟User、UserEntity对象,同时确保validate方法的返回值能正确传递(如果validate是UserValidationService的内部方法,要保证它返回的CompletableFuture也是已完成状态)。

修正后的测试代码示例

@ExtendWith(MockitoExtension.class)
class UserValidationServiceTest {

    @Mock
    UserService userService;

    @Mock
    UserEntityService userEntityService;

    @InjectMocks
    UserValidationService userValidationService;

    // 注意:@ExtendWith(MockitoExtension.class)已自动初始化Mock,无需重复调用openMocks
    // @Before
    // public void init() {
    //     MockitoAnnotations.openMocks(this);
    // }

    @Test
    public void validateUser() throws ExecutionException, InterruptedException {
        // 1. 构造测试用的模拟实体
        User mockUser = new User();
        mockUser.setUserId(1L);
        
        List<UserEntity> mockUserEntities = List.of(
                new UserEntity("US"),
                new UserEntity("ASIA"),
                new UserEntity("EUROPE")
        );

        // 2. 创建已完成的CompletableFuture,直接返回模拟数据
        CompletableFuture<User> userFuture = CompletableFuture.completedFuture(mockUser);
        CompletableFuture<List<UserEntity>> userEntityFuture = CompletableFuture.completedFuture(mockUserEntities);

        // 3. 配置Mock的方法返回行为
        Mockito.when(userService.getUser(anyString())).thenReturn(userFuture);
        Mockito.when(userEntityService.getUserEntities(anyLong())).thenReturn(userEntityFuture);

        // 4. 构造测试请求
        UserRequest request = UserRequest.builder()
                .userName("admin")
                .userEntities(List.of("US", "ASIA", "EUROPE")).build();

        // 执行测试并验证结果
        boolean result = userValidationService.validateUserCounterparty(request);
        assertTrue(result);
    }
}

额外优化说明

  • 移除冗余的@Before初始化代码:@ExtendWith(MockitoExtension.class)会自动完成Mock对象的初始化,无需手动调用MockitoAnnotations.openMocks(this)。
  • 关于validate方法:如果它是UserValidationService的私有方法,需要确保模拟的userEntities和请求中的userEntities匹配,让方法逻辑返回true的CompletableFuture;如果需要更灵活的控制,可以将方法改为包私有,或者使用Mockito Spy来部分模拟UserValidationService的行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 06:24:47