JUnit 5结合Spock测试无法并行执行问题求助
我编写了如下Spock测试代码,尝试使用JUnit 5.9.0的@Execution注解实现并行执行:
import org.junit.jupiter.api.parallel.Execution // version 5.9.0 import org.junit.jupiter.api.parallel.ExecutionMode import spock.lang.Specification import spock.lang.Unroll @Execution(ExecutionMode.CONCURRENT) class ExampleTest extends Specification { @Unroll @Execution(ExecutionMode.CONCURRENT) def "test1: should get valid #testParam"() { System.out.println("FirstParallelUnitTest first() start => " + Thread.currentThread().getName() + " id: " + Thread.currentThread().getId()); given: def test = testParam expect: test != null System.out.println("FirstParallelUnitTest first() end => " + Thread.currentThread().getName() + " id: " + Thread.currentThread().getId()); where: testParam << ["one", "two", "three", "four"] } @Unroll @Execution(ExecutionMode.CONCURRENT) def "test2: should get valid #testParam"() { System.out.println("FirstParallelUnitTest first() start => " + Thread.currentThread().getName() + " id: " + Thread.currentThread().getId()); given: def test = testParam expect: test != null System.out.println("FirstParallelUnitTest first() end => " + Thread.currentThread().getName() + " id: " + Thread.currentThread().getId()); where: testParam << ["one", "two", "three", "four"] } @Unroll @Execution(ExecutionMode.CONCURRENT) def "test3: should get valid #testParam"() { System.out.println("FirstParallelUnitTest first() start => " + Thread.currentThread().getName() + " id: " + Thread.currentThread().getId()); given: def test = testParam expect: test != null System.out.println("FirstParallelUnitTest first() end => " + Thread.currentThread().getName() + " id: " + Thread.currentThread().getId()); where: testParam << ["one", "two", "three", "four"] } }
我已在src/test/resources下创建junit-platform.properties文件,内容如下:
junit.jupiter.execution.parallel.enabled=true junit.jupiter.execution.parallel.mode.default = concurrent junit.jupiter.execution.parallel.mode.classes.default = concurrent junit.jupiter.execution.parallel.config.strategy=fixed junit.jupiter.execution.parallel.config.fixed.parallelism=2
同时在Gradle 7.6的test任务中添加了systemProperties配置:
test { testLogging { exceptionFormat = 'full' } useJUnitPlatform() systemProperties([ 'junit.jupiter.execution.parallel.enabled': 'true', 'junit.jupiter.execution.parallel.mode.default': 'concurrent', 'junit.jupiter.execution.parallel.mode.classes.default': 'concurrent', ]) }
测试依赖配置:
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") testImplementation("org.junit.jupiter:junit-jupiter-params")
还尝试在build.gradle中添加:
subprojects { tasks.withType(Test) { maxParallelForks = Runtime.runtime.availableProcessors() } }
我的处理器是i7-6600U(2核),期望看到并行执行效果,但运行测试时日志显示线程ID始终为1,所有测试串行执行,start/end顺序固定。请问如何让这些测试及其他测试实现并行执行?
解决方法
1. 确认Spock版本与JUnit 5并行支持的兼容性
Spock 2.x及以上版本才支持JUnit 5的并行执行特性,检查依赖中是否引入了正确的Spock版本,添加核心依赖:
testImplementation("org.spockframework:spock-core:2.3-groovy-4.0") testRuntimeOnly("org.junit.platform:junit-platform-launcher")
注意:Groovy版本要与Spock版本匹配,比如Spock 2.3对应Groovy 4.0,若使用Groovy 3.x则选择
2.3-groovy-3.0。
2. 移除重复的并行配置
同时在junit-platform.properties和Gradle的systemProperties中配置并行参数可能导致冲突,建议只保留其中一处配置,推荐使用junit-platform.properties。
3. 简化注解配置
类上的@Execution(ExecutionMode.CONCURRENT)已让该类下所有测试方法默认并发执行,无需给每个方法重复添加该注解。
4. 调整Gradle的进程级并行配置
maxParallelForks是Gradle进程级并行,与JUnit 5线程级并行是不同维度。你的处理器是2核,设置maxParallelForks = 2即可,避免设置为逻辑核心数导致资源竞争。
5. 优化日志打印
修改日志内容区分不同测试方法和参数,方便验证并行效果:
System.out.println("test1 start (#testParam) => " + Thread.currentThread().getName() + " id: " + Thread.currentThread().getId());
6. 检查IDE配置
确保IDE的测试运行配置未强制串行执行,比如IntelliJ IDEA中需开启"Run/Debug Configurations"里的"Parallel execution"选项。
内容的提问来源于stack exchange,提问作者tryingHard

