Answering the Core Questions
- Is
@TestMethodOrder guaranteed to be respected when @Execution(ExecutionMode.CONCURRENT) is active?
No. When a test class is marked with @Execution(ExecutionMode.CONCURRENT), the Jupiter test scheduler may start test methods on different threads in any order. The JUnit 5 documentation explicitly states that ordering annotations are ignored under concurrent execution. In practice, you’ll see the methods run in the order dictated by the scheduler, not by @Order values.
- What configuration options or annotations can enforce a specific execution order across threads?
There are a few pragmatic ways to preserve deterministic order while still taking advantage of parallelism for the rest of the suite:
@Execution(ExecutionMode.SAME_THREAD) on the specific test class (or a @Nested subclass). This forces that class’s tests to run sequentially on a single thread, and the @Order values will be respected.
- Move the ordered tests into a separate class that is not annotated with
@Execution(CONCURRENT). The rest of the test suite can remain concurrent.
- Use a custom
TestExecutionListener that synchronizes the execution of ordered methods (e.g., with a Phaser or CountDownLatch) and releases them in @Order sequence. This approach keeps the methods scheduled on multiple threads but serializes them in the desired order.
- Apply
@TestInstance(Lifecycle.PER_CLASS) together with @Order and a listener that blocks until the previous ordered test finishes. This is useful when the test instance needs to be shared across methods.
- Are there documented limits or recommended patterns for combining
@TestMethodOrder with parallel execution?
JUnit 5’s own documentation recommends avoiding the mix of @TestMethodOrder and @Execution(ExecutionMode.CONCURRENT) within the same class. The main reasons are:
- Ordering is not guaranteed, leading to flaky tests if state is shared.
- Enforcing order across threads typically serializes the tests, negating the performance benefits of concurrency.
- Shared static state is especially problematic; if tests rely on such state, the safest approach is to isolate ordered tests in a non‑concurrent class or use
@Execution(SAME_THREAD).
>**Recommended pattern**: Keep the majority of tests in concurrent classes. For any suite that requires strict ordering (e.g., integration tests that build up a shared context), create a dedicated test class or nested class, annotate it with
@Execution(ExecutionMode.SAME_THREAD), and apply
@TestMethodOrder there. This preserves overall parallelism while guaranteeing deterministic order where it matters.
Quick Code Example
@Execution(ExecutionMode.CONCURRENT)
class ConcurrentSuite {
@Test void fastTest() { … }
}
@Execution(ExecutionMode.SAME_THREAD)
@TestMethodOrder(OrderAnnotation.class)
class OrderedSuite {
@Test @Order(1) void init() { … }
@Test @Order(2) void stepOne() { … }
@Test @Order(3) void stepTwo() { … }
}
With this split, OrderedSuite runs deterministically, while ConcurrentSuite continues to run in parallel.
Follow‑up Diagnostic Detail
Do your ordered tests depend on shared static state that must be initialized in a specific order? If so, isolating them with @Execution(SAME_THREAD) is the most reliable approach.