bigywater.tech
Java · 426

JUnit 并行测试

JUnit 并行执行有七八个配置项,它们的相互作用并不直观。这篇用 16 个真实的测试,把动态与固定并行度、类并发与方法并发、@ResourceLock / @Isolated / SAME_THREAD、I/O 型与 CPU 型测试对总时间的影响逐项量出来。

4966 → 360 ms
16 个 sleep 300 ms 的测试,串行与 fixed 并行度 16 的运行时间
834 vs 795 ms
CPU 型测试 fixed 并行度 10(= 核数)与 16 的运行时间:超过核数没有收益
5005 ms
16 个测试都加 @ResourceLock("db") 后,fixed 并行度 16 下的运行时间(等于串行)

并行配置对时间的影响

实测 · 本机执行输出
  [默认(没有启用并行)] 测试 16 个,JUnit 报告的运行时间 4966 ms
  [enabled=true + mode.default=concurrent(mode.classes.default 没设,继承 mode.default),动态并行度] 测试 16 个,JUnit 报告的运行时间 670 ms
  [enabled=true + 显式写出两者都是 concurrent(动态并行度,factor = 1.0)] 测试 16 个,JUnit 报告的运行时间 669 ms
  [只有类并发:mode.default=same_thread,mode.classes.default=concurrent] 测试 16 个,JUnit 报告的运行时间 1288 ms
  [fixed 并行度 1] 测试 16 个,JUnit 报告的运行时间 5002 ms
  [fixed 并行度 2] 测试 16 个,JUnit 报告的运行时间 2524 ms
  [fixed 并行度 4] 测试 16 个,JUnit 报告的运行时间 1288 ms
  [fixed 并行度 8] 测试 16 个,JUnit 报告的运行时间 665 ms
  [fixed 并行度 16] 测试 16 个,JUnit 报告的运行时间 360 ms

CPU 型测试

实测 · 本机执行输出
  [默认(串行)] 测试 16 个,JUnit 报告的运行时间 4876 ms
  [fixed 并行度 4] 测试 16 个,JUnit 报告的运行时间 1336 ms
  [fixed 并行度 10] 测试 16 个,JUnit 报告的运行时间 834 ms
  [fixed 并行度 16] 测试 16 个,JUnit 报告的运行时间 795 ms

变回串行的写法

实测 · 本机执行输出
  [对照:16 个 I/O 测试,fixed 并行度 16] 测试 16 个,JUnit 报告的运行时间 361 ms
  [16 个测试都加 @ResourceLock("db"),fixed 并行度 16] 测试 16 个,JUnit 报告的运行时间 5005 ms
  [4 个并发的类 + 1 个 @Isolated 的类(只有 1 个 300 ms 的测试),fixed 并行度 16] 测试 17 个,JUnit 报告的运行时间 676 ms
  [SameThreadClass:@Execution(SAME_THREAD) 的类,4 个测试,fixed 并行度 16] 测试 4 个,JUnit 报告的运行时间 1282 ms
  [4 个并发的类 + 1 个 SAME_THREAD 的类] 测试 20 个,JUnit 报告的运行时间 1303 ms

实际线程

实测 · 本机执行输出
  [默认(串行)] 完成 16 个测试,实际用到的线程数 1:[main]
  [fixed 并行度 4] 完成 16 个测试,实际用到的线程数 4:[FJP-worker-1, FJP-worker-2, FJP-worker-3, FJP-worker-4]
  [fixed 并行度 16] 完成 16 个测试,实际用到的线程数 16:[FJP-worker-1, FJP-worker-10, FJP-worker-11, FJP-worker-12, FJP-worker-13, FJP-worker-14]…

分步演示

JUnit 并行测试
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12;JUnit console-standalone 1.11.3;10 个逻辑 CPU(Apple Silicon,性能核与能效核混合);每次运行是一个新的 ConsoleLauncher 进程,时间取 JUnit 报告的 Test run finished after … ms;I/O 型测试是 Thread.sleep(300),CPU 型是固定迭代次数的计算
    • 没有验证:custom 并行策略、junit.jupiter.execution.parallel.config.dynamic.factor 的其它取值、Maven Surefire 的 forkCount / parallel 与 JUnit 并行的叠加、并行下共享状态导致的数据竞争(见第 235 篇)、@ResourceLock 的 READ / READ_WRITE 模式、测试数量很大时的调度开销
    京ICP备2026067502号-1京公网安备11010502063487号