Besides sorting by an explicit priority number, what other built-in strategies does JUnit 5 provide for sorting test methods, and how would you apply one across an entire codebase without editing every test class?
answer
- OrderAnnotation / MethodName / DisplayName / Random
- junit.jupiter.testmethod.order.default
- junit-platform.properties on test classpath
- Random seed logged + junit.jupiter.execution.order.random.seed
- Alphanumeric deprecated 5.7 -> MethodName
basics
~10 sJUnit 5 ships MethodOrderer.OrderAnnotation, MethodName, DisplayName and Random. Apply one globally with the junit.jupiter.testmethod.order.default configuration parameter (for example in junit-platform.properties) instead of annotating each class. You can also implement MethodOrderer yourself.
solid answer
~50 sJupiter's `MethodOrderer` SPI has four built-in implementations: - **`OrderAnnotation`** — sorts by `@Order(int)`, ascending. - **`MethodName`** — alphanumeric by method name, then parameter list (replaced the deprecated `Alphanumeric` in 5.7). - **`DisplayName`** — alphanumeric by the resolved display name, so `@DisplayName("1. create")` sorts the report. - **`Random`** — pseudo-random. The seed comes from `junit.jupiter.execution.order.random.seed`; if unset, one is generated and **logged**, so a failure is reproducible by pinning that seed. To apply a strategy suite-wide, set the configuration parameter `junit.jupiter.testmethod.order.default` to the orderer's fully-qualified class name — typically in `junit-platform.properties` on the test classpath. Any class carrying its own `@TestMethodOrder` still wins locally. Random ordering globally is the practical use: it shakes out hidden inter-test dependencies, and the logged seed lets you replay the exact failing sequence. You can also implement `MethodOrderer` yourself — one method, `orderMethods(MethodOrdererContext)`, where you sort the mutable list of method descriptors in place.
code
properties · 2 linesjunit.jupiter.testmethod.order.default = org.junit.jupiter.api.MethodOrderer$Random
junit.jupiter.execution.order.random.seed = 424242go deeper
Name the built-in orderers and that a class-level annotation selects one; the global parameter can be a stretch answer.
Give the four orderers with what each sorts by, plus junit.jupiter.testmethod.order.default in junit-platform.properties and the precedence rule.
Lead with the operational value: random ordering plus a logged seed as a tool for finding state leaks, adopted incrementally, with the fix being isolation rather than pinned order.
Position it as suite policy — randomised ordering as a standing guard on test independence, which is what makes sharding and parallel CI safe, and the migration path for legacy modules.
## The SPI Ordering in JUnit Jupiter is a strategy interface, `org.junit.jupiter.api.MethodOrderer`, with a single method to implement: ```java void orderMethods(MethodOrdererContext context); ``` The context hands you `getMethodDescriptors()` — a **mutable** `List<MethodDescriptor>` you sort in place — plus the test class and access to configuration parameters. You return nothing; whatever order the list ends in is the execution order. ## The four built-in orderers **`MethodOrderer.OrderAnnotation`** sorts ascending by the `@Order(int)` annotation, with `Integer.MAX_VALUE / 2` for un-annotated methods. This is the explicit, intent-carrying option. **`MethodOrderer.MethodName`** sorts alphanumerically by method name, falling back to the parameter type list to break ties between overloads. It is the closest thing to JUnit 4's `MethodSorters.NAME_ASCENDING`. Historically Jupiter shipped `MethodOrderer.Alphanumeric`; it was deprecated in 5.7 in favour of `MethodName` and later removed, so old snippets using it will not compile on modern JUnit. **`MethodOrderer.DisplayName`** sorts by the *resolved display name* — that is, `@DisplayName` if present, otherwise whatever the display-name generator produced. It is the orderer to use when the ordering exists for the benefit of the report: prefix display names with `1.`, `2.`, `3.` and the report reads as a narrative without any `@Order` noise in the code. **`MethodOrderer.Random`** shuffles pseudo-randomly. The seed is taken from the configuration parameter `junit.jupiter.execution.order.random.seed`; when it is not set, Jupiter generates one and logs it at INFO level. That logging is the whole point: a random-order failure is reproducible by setting the seed from the log and rerunning. ## Applying an orderer globally Annotating every class does not scale and is easy to forget on new classes. Jupiter therefore reads a **configuration parameter**: ``` junit.jupiter.testmethod.order.default = org.junit.jupiter.api.MethodOrderer$Random ``` Note the `$` — it is a nested class, so the binary name is required. Configuration parameters can be supplied several ways; the portable one is a `junit-platform.properties` file at the root of the test classpath (`src/test/resources`). They can also be passed as JVM system properties or through the launcher API. Precedence is simple: an explicit `@TestMethodOrder` on a class beats the global default, so a scenario class can keep its `@Order` sequence while the rest of the suite runs randomised. The same pattern exists one level up for classes: `junit.jupiter.testclass.order.default` takes a `ClassOrderer`. ## Why random ordering is worth turning on Order dependencies are silent until they are catastrophic. A test that leaves a row in the database, a system property set, a static cache warm, or a mocked clock advanced, makes some *other* test pass. Nothing fails — until someone deletes an unrelated test, adds a tag filter, or shards the suite across CI agents, and then a test fails in a place with no relationship to the change. Global random ordering converts that latent bug into a flaky failure you can see now, while the code is fresh. The workflow is: enable it, watch for failures, read the logged seed, pin the seed to reproduce, then fix the *state leak* — not the order. Teams that adopt this usually leave it on in CI permanently and treat any order-related failure as a defect in the test that leaked. The cost is real, though: random order plus a genuinely dependent legacy suite produces noise, so adopt it module by module rather than flipping it on across a large old codebase in one commit. ## Writing a custom orderer Custom orderers are rare but easy. Typical motivations: run fast tests before slow ones so failures surface early; order by a project-specific annotation; put previously-failed tests first. Implement the interface, sort the descriptor list, and reference the class either in `@TestMethodOrder(MyOrderer.class)` or in the global configuration parameter. `MethodDescriptor` exposes the `Method` plus annotation lookups, so decisions can be made from any annotation you define. One subtlety worth knowing: `MethodOrderer` also declares `getDefaultExecutionMode()`, which lets an orderer state that ordered methods should run on the same thread. That is how ordering keeps meaning when parallel execution is switched on — without it, "order" would only describe the sequence in which methods are *started*. ## Summary table | Orderer | Sorts by | Typical use | |---|---|---| | `OrderAnnotation` | `@Order(int)` ascending | Deliberate scenario steps | | `MethodName` | Method name, then params | Stable, readable, no annotations | | `DisplayName` | Resolved display name | Report reads as a narrative | | `Random` | Seeded shuffle | Prove independence, hunt state leaks |
- You enable random ordering globally and one test starts failing intermittently. What is your next step?Read the seed that Jupiter logged for the failing run and set `junit.jupiter.execution.order.random.seed` to it so the exact sequence replays deterministically. Then find what the earlier tests left behind — rows, static state, system properties, a mutated singleton — and fix the leak. The fix is isolating state, not pinning the order.
- A class has its own @TestMethodOrder while junit.jupiter.testmethod.order.default is set to something else. Which wins?The class-level annotation. The configuration parameter only supplies the default for classes that do not declare an orderer themselves, so a scenario class can keep its @Order sequence while everything else runs under the global strategy.
saying these in an interview costs you the question
- Naming MethodOrderer.Alphanumeric as the current alphabetical orderer (removed; it is MethodName now).
- Thinking random ordering is irreproducible — the seed is logged and configurable.
- Writing the global parameter with a dot instead of $ for the nested class name.
- Assuming the global configuration parameter overrides a class-level @TestMethodOrder.
- Confusing MethodOrderer (methods within a class) with ClassOrderer (classes).