Which configuration controls the number of threads JUnit 5 uses for parallel test execution?
0 reputation · 14 Nov 2020, 11:35 UTC
0 reputation · 14 Nov 2020, 11:35 UTC
The goal is to understand how JUnit 5 determines the degree of parallelism when the junit.jupiter.execution.parallel.mode property is set to concurrent, especially when latency appears only under concurrent test execution. The framework defaults to using the number of available processors, but there is no standardized mechanism to override this value for an individual test suite or class without altering the global junit-platform.properties file. This lack of per‑suite configurability can lead to inconsistent parallelism levels across different build environments, making it difficult to isolate whether observed latency stems from test‑specific contention or from the underlying thread‑pool sizing.
Is there a way to specify parallelism per test class or method without modifying global properties? How does JUnit decide the pool size when no fixed parallelism is explicitly configured? What effect does the shared ForkJoinPool common pool have on latency when many test methods run concurrently?
35275 reputation · 14 Nov 2020, 14:45 UTC
JUnit 5's thread count for parallel execution is controlled by the junit.jupiter.execution.parallel.config.strategy property, together with strategy-specific settings in junit-platform.properties. There is no per-class or per-method annotation that changes the pool size — parallelism is a single engine-wide setting.
Once you enable parallelism with junit.jupiter.execution.parallel.enabled=true, the Jupiter engine builds its worker pool from the configured strategy:
availableProcessors × junit.jupiter.execution.parallel.config.dynamic.factor (factor defaults to 1, so you get roughly one thread per core).junit.jupiter.execution.parallel.config.fixed.parallelism threads.ParallelExecutionConfigurationStrategy interface, named via junit.jupiter.execution.parallel.config.custom.class.A minimal fixed-size configuration looks like this:
# src/test/resources/junit-platform.properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=4Annotations like @Execution(CONCURRENT) and @ResourceLock control which tests may run concurrently and how they contend for shared resources — they never resize the pool. If you need different parallelism for different suites, the practical options are: run those suites as separate Maven/Gradle test tasks each with its own junit-platform.properties, or use the custom strategy to compute parallelism from an environment variable or system property. This is a known limitation, not a misconfiguration on your side.
JUnit 5 submits test work to a ForkJoinPool. The likely explanation for latency that only appears under concurrent execution is pool saturation plus contention: when more tests are eligible to run than there are worker threads, the excess queue up, and wall-clock latency per test grows even though total throughput is fine. If the engine uses the common pool (behavior can vary by version and configuration), other common-pool users in the same JVM — parallel streams in your code under test, or the build tool itself — compete for the same workers. Using @ResourceLock on shared resources (ports, files, static state) can also serialize tests in ways that look like a thread-count problem but are actually lock contention.
Don't trust the config file alone — verify what the engine really created:
@Test
void printWorker() {
System.out.println(Thread.currentThread().getName());
}Run several concurrent tests and count the distinct junit-jupiter-timeout-thread/worker names (prefix varies by version; look for the ForkJoinPool-style names). Cross-check with jconsole or jcmd <pid> Thread.print while the suite runs, and watch core utilization with htop. If the observed worker count doesn't match your fixed value, confirm the properties file is actually on the test classpath — a file placed in the wrong directory silently falls back to the dynamic default, which is a common cause of "my setting is ignored" reports.
Version note: parallel execution was experimental when introduced in JUnit 5.3 and stabilized later; property names above apply to current 5.x releases. Confirm against the user guide for your exact version.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.