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

如何用Mockito测试含Thread.sleep()的try-catch中catch代码块?

测试Thread.sleep中断场景的正确姿势

你之前的尝试没用,核心原因是:你spy并中断的是一个全新的Thread实例,但执行myMethod的是测试代码所在的当前线程(或你启动的执行任务的线程),两者完全不是同一个,自然触发不了Thread.sleep(400)的中断逻辑。

下面给两种可行的解决方案:

方案一:通过线程中断模拟真实场景

这种方式不需要额外依赖,完全模拟真实环境下的线程中断逻辑:

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

class MyServiceTest {
    static class MyService {
        public void myMethod() {
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Test
    void testMyMethodWhenInterrupted() throws InterruptedException, ExecutionException {
        MyService service = new MyService();
        ExecutorService executor = Executors.newSingleThreadExecutor();

        // 提交myMethod执行任务
        Future<Void> future = executor.submit(service::myMethod);
        // 立即中断执行任务的线程
        executor.shutdownNow();

        // 捕获任务执行时抛出的异常
        Assertions.assertThatThrownBy(future::get)
                .isInstanceOf(ExecutionException.class)
                .hasCauseInstanceOf(RuntimeException.class)
                .hasRootCauseInstanceOf(InterruptedException.class);
    }
}

逻辑说明:

  1. 用ExecutorService创建单线程池,提交myMethod的执行任务
  2. 调用shutdownNow()会立即中断正在执行任务的线程
  3. 当Thread.sleep(400)被中断时,会抛出InterruptedException,进而触发myMethod中的RuntimeException
  4. 通过Future.get()获取任务执行结果,捕获到的ExecutionException中包含我们预期的异常链

方案二:用PowerMock静态Mock Thread.sleep(可选)

如果不想处理线程同步的问题,可以用PowerMock直接模拟Thread.sleep抛出异常,这种方式更简洁,但需要引入PowerMock依赖:

import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.ArgumentMatchers.anyLong;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Thread.class)
public class MyServicePowerMockTest {
    static class MyService {
        public void myMethod() {
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Test
    void testMyMethodWhenSleepInterrupted() {
        // 静态Mock Thread类
        PowerMockito.mockStatic(Thread.class);
        // 指定调用Thread.sleep时抛出InterruptedException
        PowerMockito.doThrow(new InterruptedException()).when(Thread.class);
        Thread.sleep(anyLong());

        MyService service = new MyService();

        // 验证是否抛出预期的RuntimeException
        Assertions.assertThatThrownBy(service::myMethod)
                .isInstanceOf(RuntimeException.class)
                .hasCauseInstanceOf(InterruptedException.class);
    }
}

注意事项:

  • 这种方式属于“模拟异常抛出”,并非真实的线程中断场景
  • 需要确保项目中引入了PowerMock的相关依赖,且该测试类不会影响其他测试的静态Mock状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 02:31:00