What does @DirtiesContext do, and how do its methodMode and classMode control when the context is evicted?
answer
- Dirties = close + remove from cache => rebuild
- Method => methodMode (default AFTER_METHOD)
- Class => classMode (default AFTER_CLASS)
- AFTER_EACH_TEST_METHOD = rebuild every method (expensive)
- Last resort; prefer @Transactional rollback
basics
~20 s@DirtiesContext marks the cached context as corrupted so Spring closes and removes it, forcing a fresh one to be built. methodMode controls timing when it's on a test method (default AFTER_METHOD); classMode controls timing when it's on a class (default AFTER_CLASS).
solid answer
~40 s`@DirtiesContext` tells the TestContext Framework that a test has mutated the shared cached context in a way that must not leak, so the context is evicted (closed and removed from the cache); the next test needing that configuration rebuilds it. On a **method**, `methodMode` sets timing: `AFTER_METHOD` (default) evicts after the method; `BEFORE_METHOD` evicts before it runs. On a **class**, `classMode` sets timing: `AFTER_CLASS` (default) evicts after all methods; `BEFORE_CLASS` evicts before any; `AFTER_EACH_TEST_METHOD` and `BEFORE_EACH_TEST_METHOD` evict around every method in the class. It's a correctness tool but an expensive one — each use forces a full context reload — so it should be a last resort after transactional rollback and proper cleanup. Overusing it, especially `AFTER_EACH_TEST_METHOD`, can wreck suite performance by defeating the whole cache.
code
java · 16 lines@SpringBootTest
class ContextMutationTest {
// Evict AFTER this method: it permanently corrupts a singleton.
@Test
@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD)
void replacesGlobalCacheState() { /* ... */ }
}
// Class-level: rebuild once before the whole class runs.
@SpringBootTest
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
class NeedsPristineContextTest {
@Test void a() { }
@Test void b() { }
}go deeper
Know it forces Spring to rebuild the context, and that method default is after the method, class default is after the class.
Enumerate all methodMode and classMode values with their timing and defaults, and know it's expensive.
Choose @DirtiesContext only for genuine context corruption, preferring @Transactional/cleanup, and recognize AFTER_EACH_TEST_METHOD as a perf anti-pattern.
Set team policy that @DirtiesContext requires justification in review, and design tests (transactional, resettable mocks) so it's almost never needed.
## What 'dirties' means Because the cache shares one physical context (and its singleton beans) across tests, a test that **irreversibly mutates** that context — replaces a bean, corrupts in-memory shared state, closes a resource, changes global config — would poison every later test that reuses it. `@org.springframework.test.annotation.DirtiesContext` marks the context as **dirty**: the framework **closes** it and **removes it from the cache**, so the next test requiring that configuration gets a **freshly built** context. ## Where you can put it and which mode applies - **On a test method** ⇒ the `methodMode` attribute governs timing. - **On a test class** ⇒ the `classMode` attribute governs timing. ### methodMode (`DirtiesContext.MethodMode`) - `AFTER_METHOD` — **default**. Evict the context **after** the annotated method finishes. Use when the method corrupts state as it runs. - `BEFORE_METHOD` — evict **before** the method runs, guaranteeing this method starts against a pristine context (useful when a *previous* test may have dirtied it and you need a clean slate for this one). ### classMode (`DirtiesContext.ClassMode`) - `AFTER_CLASS` — **default**. Evict once, **after** the whole class completes. Cheapest class-level option. - `BEFORE_CLASS` — evict **before** the class starts, so the class begins fresh. - `AFTER_EACH_TEST_METHOD` — evict **after every** method in the class (rebuild between each test). Very expensive. - `BEFORE_EACH_TEST_METHOD` — evict **before every** method. ## Defaults recap - Method-level default timing: `AFTER_METHOD`. - Class-level default timing: `AFTER_CLASS`. ## Hierarchy / bean-definition nuances `@DirtiesContext` also has a `hierarchyMode` attribute (`EXHAUSTIVE` vs `CURRENT_LEVEL`) that controls, for a `@ContextHierarchy`, whether the whole hierarchy or just the current level is evicted. For most flat `@SpringBootTest` setups this doesn't matter. ## Cost and alternatives Each eviction forces a **full context rebuild** on next use — the single most expensive thing in the suite. So `@DirtiesContext` is a correctness sledgehammer: - Prefer **`@Transactional`** tests (automatic rollback) for DB state — no eviction needed. - Prefer explicit **`@BeforeEach`/`@AfterEach` cleanup** or resetting mocks/`@MockitoBean` (which Spring resets automatically between methods) over dirtying. - Reserve `@DirtiesContext` for genuinely **unrecoverable** context corruption: replacing a bean's internal state permanently, tests of `ApplicationContext` refresh/shutdown, or mutating a singleton with no reset path. ## Anti-patterns - Class-level `AFTER_EACH_TEST_METHOD` on a `@SpringBootTest` — rebuilds the entire Spring context between every method, often the biggest single cause of a slow suite. - Using `@DirtiesContext` to 'fix' a flaky test whose real problem is missing cleanup or a non-transactional write; it hides the design flaw at high cost. ## Execution mechanics Eviction is performed by the `DirtiesContextTestExecutionListener` (and `DirtiesContextBeforeModesTestExecutionListener` for the BEFORE modes), which are registered by default in the TestContext Framework.
- You use @DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) and the suite crawls. Why, and what's the fix?It rebuilds the entire Spring context after every single method, so you pay full startup cost per test. Usually the real need is per-test state reset — use @Transactional rollback, @BeforeEach/@AfterEach cleanup, or mock reset instead, reserving eviction for genuine unrecoverable corruption.
- When would BEFORE_METHOD be the right methodMode rather than AFTER_METHOD?When this particular test needs to start from a pristine context because an earlier test in the run may have left the shared context in an unknown state, and you'd rather guarantee cleanliness going in than clean up after.
- Does @DirtiesContext help with database rows left behind by a test?Not really — it rebuilds the Spring context, not the database. For leaked rows use @Transactional (rollback) or explicit cleanup; @DirtiesContext only matters when the ApplicationContext itself is corrupted.
saying these in an interview costs you the question
- Thinking @DirtiesContext rolls back the database (it evicts the Spring context, not DB rows)
- Believing the class-level default is AFTER_EACH_TEST_METHOD (it's AFTER_CLASS)
- Using @DirtiesContext as the default fix for flaky/order-dependent tests
- Not realizing each dirty forces a full, expensive context rebuild