Mockito如何验证异步线程中执行的指定方法是否被调用?
问题根因
你的业务代码将component.runJob()放在独立子线程中异步执行,单元测试主线程调用完enact方法后会立刻执行校验逻辑,此时子线程尚未完成调度、还未执行runJob方法,因此mock框架检测不到对应调用,触发报错。
修复方案
方案1:使用Mockito内置超时校验(最简改造)
Mockito提供timeout方法,可以等待指定时间直到方法被调用,无需修改业务代码:
void testVTService_Success() { when(xBuilder.buildInputPayload(any(Request.class))).thenReturn(inputPayloadWithAllArguments); activity.enact(TestConstants.request); // 最多等待1秒验证方法被调用,可根据实际场景调整超时时间 verify(component, timeout(1000).times(1)).runJob(any(XInput.class)); }
方案2:使用CountDownLatch手动同步(灵活可控)
如果需要更精细的线程执行状态管控,可以用CountDownLatch做线程同步:
void testVTService_Success() throws InterruptedException { CountDownLatch latch = new CountDownLatch(1); // 监听runJob调用,调用完成后减少latch计数 doAnswer(invocation -> { Object result = invocation.callRealMethod(); latch.countDown(); return result; }).when(component).runJob(any(XInput.class)); when(xBuilder.buildInputPayload(any(Request.class))).thenReturn(inputPayloadWithAllArguments); activity.enact(TestConstants.request); // 最多等待1秒,若等待超时会抛出中断异常说明线程未正常执行 boolean isExecuted = latch.await(1, TimeUnit.SECONDS); assertTrue(isExecuted, "runJob方法未在指定时间内执行,线程可能未正常启动"); verify(component, times(1)).runJob(any(XInput.class)); }
方案3:改造业务代码提升可测试性(最佳实践)
避免在业务代码中直接new Thread,改为注入线程执行器,测试时替换为同步执行器,从根源消除异步问题:
业务代码改造:
// 构造函数注入Executor,生产环境注入线程池,测试环境注入同步执行器 public YourClass(Executor executor, XBuilder xBuilder, Component component) { this.executor = executor; this.xBuilder = xBuilder; this.component = component; } void enact(@NonNull final Request request) { XInput input = this.xBuilder.buildInputPayload(request); executor.execute(() -> this.component.runJob(input)); return; }
单元测试改造:
测试时直接传入同步执行器,所有任务都在测试主线程执行,无需额外等待逻辑:
void testVTService_Success() { // 同步执行器,提交的任务会立刻在当前线程执行 Executor synchronousExecutor = Runnable::run; // 初始化被测试类时传入同步执行器 YourClass activity = new YourClass(synchronousExecutor, xBuilder, component); when(xBuilder.buildInputPayload(any(Request.class))).thenReturn(inputPayloadWithAllArguments); activity.enact(TestConstants.request); verify(component, times(1)).runJob(any(XInput.class)); }
如果需要验证线程是否正常启动,可mock Executor验证execute方法是否被正常调用即可。
内容的提问来源于stack exchange,提问作者Diksha Goyal
相关产品推荐
相关产品推荐

