When a test class inherits from a base class with its own @BeforeAll, and there are multiple @BeforeAll methods, in what order does JUnit 5 run them — and how does @AfterAll mirror that?
answer
- Setup: superclass before subclass
- Teardown: subclass before superclass (reverse/LIFO)
- Same-class multiple @BeforeAll order is unspecified
- @Order/@MethodOrderer is for @Test, not lifecycle hooks
- Don't make @BeforeAll methods depend on each other
basics
~20 sInherited @BeforeAll methods from a superclass run before the subclass's @BeforeAll; @AfterAll runs in the reverse order (subclass first, then superclass). Multiple @BeforeAll methods in the same class run in an unspecified order unless you set one with @Order.
solid answer
~50 sJUnit 5 runs @BeforeAll methods top-down through the class hierarchy: a superclass's @BeforeAll runs before the subclass's, mirroring how you build context from the most general to the most specific. @AfterAll mirrors this in reverse — subclass @AfterAll first, then superclass — so teardown unwinds in the opposite order of setup, like a stack. Within a single class, if there are multiple @BeforeAll methods their relative order is deterministic but not the source order you might assume, so you shouldn't depend on it; @MethodOrderer affects @Test methods, not lifecycle methods, so if you truly need ordering among lifecycle hooks you generally consolidate them or model them as ordered extensions. The practical guidance I give teams: don't write @BeforeAll methods that depend on each other's order — make each self-contained — because relying on unspecified ordering is a latent flaky-test source.
code
java · 19 linesimport org.junit.jupiter.api.*;
class BaseTest {
@BeforeAll static void baseSetup() { System.out.println("1 base @BeforeAll"); }
@AfterAll static void baseTeardown(){ System.out.println("4 base @AfterAll"); }
}
class ChildTest extends BaseTest {
@BeforeAll static void childSetup() { System.out.println("2 child @BeforeAll"); }
@AfterAll static void childTeardown(){ System.out.println("3 child @AfterAll"); }
@Test void t() { /* ... */ }
}
// Output order:
// 1 base @BeforeAll (superclass setup first)
// 2 child @BeforeAll (then subclass setup)
// ... test runs ...
// 3 child @AfterAll (subclass teardown first)
// 4 base @AfterAll (then superclass teardown -> reverse of setup)go deeper
Likely unaware of hierarchy ordering; can at least state @BeforeAll runs before tests.
Knows superclass setup runs before subclass setup but may be fuzzy on teardown direction.
States the LIFO teardown rule and that same-class @BeforeAll ordering is unspecified.
Treats lifecycle ordering as a design risk: avoids order-coupled hooks, uses ordered extensions, and understands static method-hiding vs overriding under each lifecycle mode.
## Setup of the question With **inheritance**, a test class can `extends` a **base/parent test class**. Both may declare lifecycle methods. The question is: in what order do the once-per-class hooks fire, and how does teardown relate to setup? ## Rule 1 — superclass before subclass for 'Before' hooks JUnit 5 executes **`@BeforeAll` methods inherited from superclasses before** the subclass's own `@BeforeAll`. The intuition: you establish the **more general context first**, then layer the specific class's setup on top. (The same top-down rule applies to `@BeforeEach`.) ## Rule 2 — teardown unwinds in reverse (like a stack) `@AfterAll` (and `@AfterEach`) run in the **opposite** order: the **subclass's `@AfterAll` runs first, then the superclass's**. This is the classic **stack/LIFO** discipline: the last thing set up is the first torn down, so each layer tears down while the layers it depended on are still present. Setup order = general→specific; teardown order = specific→general. ## Rule 3 — multiple hooks in the same class are not source-ordered If one class has **several `@BeforeAll` methods**, JUnit does **not** guarantee they run in the order they appear in the file. The order is **deterministic but intentionally unspecified/algorithmic**, so you must **not** rely on it. `@MethodOrderer`/`@Order` semantics apply to **`@Test` methods**, not to lifecycle methods, so you can't simply order lifecycle hooks the way you order tests. ## Why this matters at a design level Depending on lifecycle ordering you don't control is a **latent flaky-test risk**: a JUnit upgrade or refactor can change the apparent order and break setup that secretly assumed it. The robust designs: - **Make each `@BeforeAll` self-contained** — no hidden dependency on another `@BeforeAll` having run first. - **Consolidate** dependent setup into a single method where order is explicit and local. - For cross-cutting, ordered lifecycle, use **JUnit 5 extensions** with `@Order` on `@RegisterExtension` fields (extension ordering *is* controllable) rather than scattering ordered `@BeforeAll` methods. ## Interaction with lifecycle mode Under the default **PER_METHOD** lifecycle these hooks are static; static methods are **not polymorphically overridden**, so a subclass `@BeforeAll` doesn't 'override' the parent's — **both run** (parent then child) unless they have the same signature and hide each other. Under **PER_CLASS**, they're instance methods and normal method-hiding/overriding rules can come into play, which is another reason to keep names distinct. ## One-line summary Setup flows superclass→subclass and teardown unwinds subclass→superclass (LIFO); ordering *among* same-class `@BeforeAll` methods is unspecified, so never depend on it.
- How can you get controllable ordering for cross-cutting lifecycle logic?Use JUnit 5 extensions registered via @RegisterExtension fields and annotate them with @Order; extension ordering is controllable, unlike the order among multiple @BeforeAll methods. This is the clean way to sequence reusable setup/teardown.
- Does a subclass @BeforeAll override the superclass one under the default lifecycle?No. Under PER_METHOD they're static, and static methods aren't polymorphically overridden — both run (superclass first, then subclass) unless identical signatures cause method hiding. Keep names distinct to avoid surprises.
saying these in an interview costs you the question
- Assuming @BeforeAll methods run in file/source order
- Thinking subclass @AfterAll runs after superclass @AfterAll
- Believing a subclass @BeforeAll overrides (replaces) the parent's
- Using @Order to sequence lifecycle methods (it targets @Test)