Gradle的test任务默认串行执行测试类,即使启用org.gradle.parallel=true也仅作用于模块间;需显式配置maxParallelForks、forkEvery及forkOptions.memoryMaximumSize等参数才能实现单任务内并发,并注意测试隔离性与日志/内存优化。

test任务默认不并行,必须显式启用
Gradle 的 test 任务本身默认是串行执行所有测试类的,哪怕你已开启 org.gradle.parallel=true,它也只影响模块间并行,不影响单个 test 任务内部的测试方法或测试类调度。这是最常被误解的一点。
要让 test 任务真正并发跑测试,得在构建脚本里单独配置其 ForkOptions 和并行策略:
-
maxParallelForks控制最多开几个 JVM 进程(不是线程),设为Runtime.runtime.availableProcessors()是较稳妥的选择 -
forkEvery可强制每运行 N 个测试类就重启 fork 进程,防止内存泄漏累积(尤其适合老项目) - 避免设
maxParallelForks > 4在普通开发机上,容易因 GC 压力反而拖慢整体速度
Java/Kotlin项目中正确配置test并行的写法
在 build.gradle(Groovy)或 build.gradle.kts(Kotlin DSL)中添加以下内容即可生效:
test {
maxParallelForks = (Runtime.runtime.availableProcessors() / 2).takeIf { it > 1 } ?: 1
forkEvery = 50
// 可选:防止中文乱码或日志截断
systemProperty 'file.encoding', 'UTF-8'
}
注意:maxParallelForks 是整数,不能写成小数;forkEvery = 50 表示每执行 50 个测试类就换一个新 JVM,适合有静态状态污染的老测试。
如果用 Kotlin DSL,记得用 maxParallelForks.set(...) 写法(Gradle 7.0+ 推荐),否则可能被静默忽略。
并行后常见失败原因和绕过方式
开启并行后,原本能过的测试突然失败,大概率是测试间存在隐式共享状态,比如:
- 共用同一个临时目录(
Files.createTempDirectory未加唯一前缀) - 读写同一份配置文件或数据库连接池(未隔离 H2 内存库实例)
- 使用
@BeforeClass或静态字段缓存了不可重入对象(如ObjectMapper配置被多线程修改)
快速验证是否是并发问题:加 --no-parallel 参数重跑一次,如果通过,基本可锁定。临时解法是在 test 块里加上 useUnsharedClassLoader()(Gradle 7.4+),但治标不治本,建议优先重构测试隔离性。
别忘了关掉干扰项:testLogging 和堆内存
这两个设置看似无关,实则对 test 执行耗时影响显著:
-
testLogging设为events "passed", "failed", "skipped"会大幅降低输出吞吐,尤其当测试量大时;生产环境建议关闭,CI 中用--console=plain替代 - JVM 堆内存不足会导致频繁 GC,
test任务 fork 出的每个子进程都受org.gradle.jvmargs影响,但子进程不会自动继承父进程内存——必须显式配forkOptions.memoryMaximumSize - 例如:
forkOptions.memoryMaximumSize = "2g",否则默认只有 512m,在大量 mock 或集成测试下极易 OOM
真正卡顿的往往不是 CPU,而是 GC 暂停或 I/O 等待;看到 test 耗时波动剧烈,先查子进程内存和日志输出级别。











