skip to content

What is the difference between @BeforeEach/@AfterEach and @BeforeAll/@AfterAll in JUnit 5?

level: middleimportance: must knowfreq 65%

answer

  1. Each = per test (many times); All = per class (once)
  2. All = expensive shared setup; Each = fresh fixture per test
  3. Default PER_METHOD: All must be static, Each must be instance
  4. @TestInstance(PER_CLASS) makes All non-static
  5. Trade-off: cost (All) vs isolation (Each)

basics

~20 s

@BeforeEach/@AfterEach run before and after every single test. @BeforeAll/@AfterAll run only once for the whole test class — before any test and after all tests. The 'Each' ones are for per-test setup; the 'All' ones are for expensive shared setup.

solid answer

~40 s

@BeforeEach and @AfterEach run around every @Test method, giving each test a fresh fixture and isolation. @BeforeAll and @AfterAll run exactly once per test class — @BeforeAll before the first test, @AfterAll after the last — and are for expensive, shareable setup like starting a database container or a server you don't want to recreate per test. Under the default PER_METHOD lifecycle, @BeforeAll/@AfterAll must be static (they run with no test instance), while @BeforeEach/@AfterEach must be instance (non-static, non-private). The trade-off is cost vs isolation: 'All' methods are faster because they run once but the shared state they create is mutable across tests, so you risk cross-test coupling; 'Each' methods are slower but keep tests independent. Switching to @TestInstance(PER_CLASS) lets @BeforeAll/@AfterAll be non-static.

go deeper

for a junior

Knows 'Each' runs per test and 'All' runs once per class, and that 'All' is for expensive shared setup.

for a middle

Explains the static requirement under PER_METHOD, the cost-vs-isolation trade-off, and pairs @BeforeAll resources with @AfterAll cleanup.

for a senior

Discusses PER_CLASS lifecycle implications, keeping shared resources non-mutating, inheritance ordering, and resetting per-test state on top of a shared resource.

for a principal

Reasons about suite-wide performance vs isolation budgets, safe sharing of heavyweight fixtures across parallel tests, and conventions/base classes that prevent @BeforeAll-induced flakiness.

## Two granularities of lifecycle JUnit 5 (Jupiter) gives you **four** lifecycle hooks that wrap your `@Test` methods, split along one axis: *how often they run*. - **`@BeforeEach` / `@AfterEach`** run **once per test method**. With 10 tests, each runs 10 times. Purpose: build and dispose a **fresh fixture** for every test so tests are isolated. - **`@BeforeAll` / `@AfterAll`** run **once per test class**. `@BeforeAll` runs before the *first* test in the class; `@AfterAll` runs after the *last* test completes. Purpose: one-time, **expensive, shareable** setup/teardown. Nesting order for a single test, top to bottom: `@BeforeAll` (once) → for each test { `@BeforeEach` → `@Test` → `@AfterEach` } → `@AfterAll` (once). ## Why two levels exist — cost vs isolation Some setup is cheap and must be fresh: `new`-ing the object under test, resetting a counter. Do that in `@BeforeEach` — cheap, and freshness guarantees **test independence** (no test sees another's leftovers). Other setup is **expensive**: spinning up an in-memory or Testcontainers database, starting an embedded HTTP server, loading a large file. Recreating it before every test would make the suite crawl. Put it in `@BeforeAll` so it happens **once** and all tests share it. The price: that shared resource is *mutable and shared*, so a careless test can leave state that another test sees — reintroducing coupling. The discipline is to keep the `@BeforeAll` resource *read-only or self-resetting*, and do per-test mutation/reset in `@BeforeEach`. ## The static rule (and the lifecycle that changes it) By default JUnit uses **`PER_METHOD` test-instance lifecycle**: it creates a *new instance of the test class for each test*. Because `@BeforeAll`/`@AfterAll` conceptually belong to the *class*, not any one instance, **under the default lifecycle they must be `static`** — there's no single instance for them to run on. `@BeforeEach`/`@AfterEach` run on the per-test instance, so they must be **non-static** (and non-private). If you annotate the class with **`@TestInstance(TestInstance.Lifecycle.PER_CLASS)`**, JUnit creates **one** instance for the whole class. Now `@BeforeAll`/`@AfterAll` *can* be non-static (they have an instance to run on), and you can keep mutable setup state in instance fields. The trade-off: instance fields now persist *across tests*, so you lose the automatic reset and must manage state yourself. ## Inheritance All four are inherited from superclasses (unless overridden/hidden). For ordering across a hierarchy: superclass `@BeforeAll`/`@BeforeEach` run **before** subclass ones; subclass `@AfterEach`/`@AfterAll` run **before** superclass ones (symmetric, outermost-last). `@BeforeAll`/`@AfterAll` being static are *hidden* (not overridden) if redeclared in a subclass. ## JUnit 4 mapping These replace JUnit 4's `@Before`/`@After` (now `@BeforeEach`/`@AfterEach`) and `@BeforeClass`/`@AfterClass` (now `@BeforeAll`/`@AfterAll`). Same conceptual split, new names, package `org.junit.jupiter.api`. ## Picking the right one Default to `@BeforeEach` for setup — it's safer (isolation). Promote to `@BeforeAll` *only* when the setup is genuinely expensive and safely shareable. Pair every `@BeforeAll` resource that holds a handle (connection, server, container) with an `@AfterAll` that closes it, so you don't leak resources across the suite.

  • Why must @BeforeAll normally be static but @BeforeEach must not be?
    Under the default PER_METHOD lifecycle JUnit creates a new test instance per test, so @BeforeAll (which belongs to the class, running once before any instance is needed for a given test) has no single instance — hence static. @BeforeEach runs on the freshly created per-test instance, so it must be an instance (non-static) method.
  • How would you start an embedded database once but reset its data between tests?
    Start/stop the database in @BeforeAll/@AfterAll (expensive, shared, once), and in @BeforeEach clear and re-seed the tables (cheap, per-test). That combines a single expensive resource with fresh per-test state.

saying these in an interview costs you the question

  • Saying @BeforeAll runs before every test (it runs once)
  • Forgetting that @BeforeAll/@AfterAll are static under the default lifecycle
  • Putting per-test mutable setup in @BeforeAll and getting cross-test coupling
  • Thinking PER_CLASS is the default (PER_METHOD is)

context