JUnit 5 Parallel Execution

How to configure parallel test execution, class-level defaults, exclusive control, and access modes

Parallel Test Execution

By default, all test methods run sequentially on a single thread. JUnit 5 can execute tests in parallel when configured.

Enabling Parallel Execution

Create junit-platform.properties at the classpath root and enable parallel execution.

/test/resource/junit-platform.properties

junit.jupiter.execution.parallel.enabled=true

This setting alone does not make test methods parallel. To run methods concurrently, set @Execution(ExecutionMode.CONCURRENT) on the test class. SAME_THREAD runs tests on the same thread as the parent and is the default.

Changing the Default Execution Mode

Set the following property to make the default method execution mode concurrent.

junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent

Some tests are excluded from this default concurrent mode, including test classes using Lifecycle.PER_CLASS and ordered tests except MethodOrderer.Random. If such tests are thread-safe and you still want them to run concurrently, explicitly add @Execution(ExecutionMode.CONCURRENT).

Changing the Top-Level Class Default

junit.jupiter.execution.parallel.mode.classes.default=concurrent changes only the default execution mode for top-level classes. In that configuration, different test classes can run on different threads while methods inside each class still run sequentially.

Execution by Setting

The combination of junit.jupiter.execution.parallel.mode.default and junit.jupiter.execution.parallel.mode.classes.default produces four patterns.

  • Both same_thread: classes and methods run sequentially.
  • Method same_thread, class concurrent: classes run in parallel, methods in each class run sequentially.
  • Method concurrent, class same_thread: methods inside a class run in parallel, classes run sequentially.
  • Both concurrent: classes and methods all run in parallel.

Parallel execution Parallel execution Parallel execution Parallel execution

Changing Parallelism

With the dynamic strategy, junit.jupiter.execution.parallel.config.dynamic.factor multiplies the number of available processors to decide the number of parallel threads.

junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.dynamic.factor=2

The factor can also be a decimal. JUnit uses BigDecimal internally and converts the calculated value to int.

For a fixed value, use fixed and specify junit.jupiter.execution.parallel.config.fixed.parallelism.

junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.fixed.parallelism=6

For custom parallelism, implement ParallelExecutionConfigurationStrategy and specify it with junit.jupiter.execution.parallel.config.custom.class.

Exclusive Control

Exclusive control prevents problems when multiple tests access a shared resource at the same time. Use @ResourceLock on a class or method. Tests with the same lock key are synchronized.

Access Modes

@ResourceLock supports access modes with ResourceAccessMode.

Previous process Later process Later process
READ READ Can run
READ READ_WRITE Waits
READ_WRITE READ Waits
READ_WRITE READ_WRITE Waits

READ can run in parallel with other reads, but READ_WRITE is exclusive. Use READ for tests that only read data and READ_WRITE for tests that update data.