In JUnit 5 (Jupiter), what order are the @Test methods inside one test class executed in when you do not configure anything, and what does that imply for how those tests must be written?
answer
- No orderer by default
- Deterministic, intentionally non-obvious
- Not source order, not alphabetical
- May change between JUnit versions
- static mutable field = order-dependency smell
basics
~20 sJupiter applies no orderer by default, so methods run in a deterministic but intentionally non-obvious order — not source order, not alphabetical — and it may change between versions. Each test must therefore pass independently, in any order.
solid answer
~50 sJUnit Jupiter deliberately does **not** run test methods in source order or alphabetical order. With no `@TestMethodOrder` present, the engine sorts methods with an internal, hash-based algorithm: the result is deterministic for a given JUnit version and class, but intentionally unpredictable to a reader, and the JUnit team reserves the right to change it. JUnit 4 behaved similarly (`MethodSorters.DEFAULT`) unless you added `@FixMethodOrder`. The reason is partly technical — reflection gives no reliable declaration order — and mostly pedagogical: tests that depend on each other break under tag filtering, rerun-failed, running a single test from the IDE, and parallel execution. So each method should build the state it needs (fresh fixtures, `@BeforeEach`) and assert only on that. If you genuinely need an order — a long scenario, one expensive fixture — you opt in explicitly with `@TestMethodOrder(MethodOrderer.OrderAnnotation.class)` plus `@Order(n)`, and you accept that the class is now a sequence rather than a set of independent tests.
code
java · 15 linesclass UserServiceTest {
private static Long createdId;
@Test
void createsUser() {
createdId = service.create("ann");
assertNotNull(createdId);
}
@Test
void findsUser() {
assertNotNull(service.find(createdId)); // NPE when this runs first
}
}go deeper
Recall the rule: no guaranteed order, so never let one test depend on another; put shared setup in @BeforeEach.
Explain why — reflection gives no declaration order, and the design forces independence — and name the opt-in escape hatch (@TestMethodOrder plus @Order).
Talk about how order dependencies actually surface (single-test runs, filters, rerun-failed, parallelism) and how you would hunt them down with random ordering and per-test data isolation.
Frame it as a suite-health policy: independence is what makes sharding, parallelism and rerun-failed possible; ordered classes are a deliberate, contained exception with a stated cost.
## The rule In JUnit Jupiter (JUnit 5), the test methods of a class are executed in a **deterministic but intentionally non-obvious order** unless you explicitly configure a `MethodOrderer`. "Deterministic" means: same class, same JUnit version, same JVM → same order every run. "Non-obvious" means: it is *not* the order the methods appear in the source file, and it is *not* alphabetical. Internally the engine sorts by a hash derived from the method name and parameter types, so the sequence looks arbitrary to a human reader. ## Why not source order? Two reasons. **Technical.** The JVM gives no guarantee about the order `Class#getDeclaredMethods()` returns members. The Javadoc explicitly says the elements are in no particular order. HotSpot happens to return something stable per compilation, but it is not contractual and has historically varied. A framework that promised source order would be promising something the platform does not provide. **Deliberate design.** Even if source order were available, JUnit does not want you leaning on it. A test suite is a *set* of independent facts, not a script. Once test B only passes because test A ran first, several everyday operations break: - Running one test alone from the IDE (`Run 'shouldChargeCard'`) fails, because the setup lived in a different method. - Tag or name filters that select a subset silently change the outcome. - "Rerun failed tests" reruns only some of the chain. - Parallel execution scrambles the assumption entirely. - Deleting or renaming an unrelated test changes the hash order and breaks something far away. The non-obvious ordering exists so those defects surface *early*, in development, rather than at 2 a.m. in CI. ## What "deterministic" does and does not promise It promises reproducibility within one setup, which is useful when you are debugging: a failure caused by ordering will keep reproducing locally. It promises **nothing** across JUnit versions. The Jupiter documentation states the algorithm may change, so upgrading a patch version can legitimately reshuffle your class. Treat the default order as an implementation detail you observe, never as a contract you code against. ## How this bites in practice The classic shape is a mutable field on the test class: ```java class UserServiceTest { private static Long createdId; // shared across methods @Test void createsUser() { createdId = service.create("ann"); } @Test void findsUser() { assertNotNull(service.find(createdId)); } // NPE if run first } ``` A second shape is shared external state: test A inserts rows, test B counts them; test A registers a mock's behaviour on a static singleton, test B consumes it. Note also that Jupiter creates a **new instance of the test class per test method** by default, so instance fields are reset — which is exactly why order-dependent code usually degenerates into `static` fields or external state. Both make the dependency easy to spot in review: a `static` mutable field in a test class is a smell. ## Writing order-independent tests - Put shared, cheap setup in `@BeforeEach` so each method starts from the same known state. - Put expensive one-time setup in `@BeforeAll` (a container/server/schema) but keep it **read-only or reset per test**; a shared resource is fine, shared *mutation* is not. - Roll back or truncate data between tests (transactional test support, `@AfterEach` cleanup, throwaway containers). - Give each test its own unique data (random e-mails, generated keys) so two tests cannot collide. - Prove independence by shuffling: configure `MethodOrderer.Random` temporarily, or run single tests in isolation. If a test only passes in a suite, it is not a test yet. ## When you legitimately want an order There are real cases: an end-to-end scenario where each step is expensive and re-doing it per test would triple the suite time; a migration or workflow test where the steps *are* the specification. In those cases opt in explicitly — `@TestMethodOrder(MethodOrderer.OrderAnnotation.class)` with `@Order(n)` — and keep the ordered class small and clearly named, because you have traded away rerun-single-test, filtering, and parallelism inside it. Making the intent explicit also tells the next reader that the sequence is deliberate rather than accidental. ## Contrast with JUnit 4 JUnit 4 had the same philosophy: `MethodSorters.DEFAULT` is a deterministic hash order, `MethodSorters.NAME_ASCENDING` and `JVM` were opt-in via `@FixMethodOrder`. Jupiter replaced that with the pluggable `MethodOrderer` SPI, which is strictly more capable (built-in orderers, a global default, custom implementations), but the default answer to "what order do my tests run in?" is unchanged: one you should not depend on.
- How would you prove that a test class really is order-independent?Run it with a randomising orderer — set `@TestMethodOrder(MethodOrderer.Random.class)` or the `junit.jupiter.testmethod.order.default` configuration parameter — several times, and separately run each test alone (IDE single-test run or a name filter). If a test only passes inside the suite, it depends on a neighbour. Some teams keep random ordering on permanently in CI so the dependency shows up as a flaky failure with a logged seed you can replay.
- Jupiter creates a new test-class instance per test method. Doesn't that already prevent order dependencies?It removes one channel: instance fields are reset for every test method, so state cannot leak through them. It does nothing about `static` fields, the database, files, system properties, a shared container, or a mocked singleton. Those are where real order dependencies live, and they survive the fresh instance.
Think of a test class as a bag of marbles, not a chain of dominoes. JUnit deliberately shakes the bag so you notice if you have secretly glued the marbles together.
saying these in an interview costs you the question
- Saying tests run top-to-bottom in source order.
- Saying the default order is alphabetical (that is JUnit 4's opt-in NAME_ASCENDING, not any default).
- Claiming the order is random each run — it is deterministic, just not obvious.
- Treating the observed default order as a stable contract you can rely on after a JUnit upgrade.
- Fixing an order-dependent suite by adding @Order instead of removing the shared mutable state.