如何用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); } }
逻辑说明:
- 用
ExecutorService创建单线程池,提交myMethod的执行任务 - 调用
shutdownNow()会立即中断正在执行任务的线程 - 当
Thread.sleep(400)被中断时,会抛出InterruptedException,进而触发myMethod中的RuntimeException - 通过
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
相关产品推荐
相关产品推荐

