How does a disabled test interact with lifecycle callbacks, fixtures, and test reporting, and what risks come with accumulating disabled tests at scale?
answer
- Skipped = body + per-test @BeforeEach/@AfterEach don't run
- Reported as 'skipped', separate from pass/fail
- Don't rely on a disabled test's side effects
- Green build hides growing skip count = false coverage
- Quarantine/fix vs disable for flaky tests
basics
~20 sA disabled test is skipped entirely - its body and its @BeforeEach/@AfterEach for that test do not run, though class-level setup may still happen. It shows as 'skipped', not passed. Lots of disabled tests quietly remove coverage, so track and prune them.
solid answer
~50 sWhen @Disabled (or a conditional that resolves to disabled) skips a test, JUnit does not invoke that test's method or its per-method lifecycle callbacks (@BeforeEach/@AfterEach) for it - there is nothing to set up or tear down. The result is reported as 'skipped' in the count, distinct from passed and failed, and the reason string (or the unmet condition) is surfaced. The danger at scale is silent coverage loss: a green build can hide dozens of skipped tests, so a feature looks 'tested' when it isn't. Mitigations include failing CI on un-ticketed @Disabled, reporting skipped counts as a quality signal, periodic audits to re-enable or delete, and preferring conditional annotations so environment-gated tests still run where they should. For flaky tests specifically, weigh disabling against quarantining (run but don't fail the build) or fixing the root cause - disabling is the bluntest option and the easiest to forget.
go deeper
Understands a disabled test is skipped and shows as 'skipped' rather than passing.
Knows the per-test lifecycle callbacks don't run for a skipped test and that skipped is a distinct report category.
Articulates the silent-coverage-loss risk, the danger of relying on a skipped test's side effects, and mitigation tactics (CI guards, audits, conditionals).
Owns the org-level strategy for flaky/disabled tests - quarantine vs disable vs delete, skip-count as a tracked quality signal, and enforcement that keeps disabling accountable and time-boxed.
## What 'skipped' actually means for execution A **lifecycle callback** is a method JUnit runs around your tests to set up and clean up shared state: `@BeforeEach`/`@AfterEach` run before/after *each* test method, and `@BeforeAll`/`@AfterAll` run once before/after *all* tests in the class. When a test is **disabled** (via `@Disabled` or a conditional annotation that resolves to disabled), JUnit determines this *before* attempting to run the test, so: - The **test method body does not execute**. - The **`@BeforeEach`/`@AfterEach`** callbacks tied to *that test* do not run for it - there is nothing to prepare or clean up. - Class-level setup (`@BeforeAll`) still runs once for the class if *any* test in it could run; a fully disabled class generally won't run its instance-level per-test fixtures for the skipped tests. The key takeaway: **don't rely on a disabled test's side effects** (e.g. it seeding data another test reads) - skipping it removes those side effects too, which can cascade into failures elsewhere. ## How it is reported A skipped test is counted in its **own category** - `skipped` - alongside `passed` and `failed`. It is *not* a pass. Build tools and CI dashboards typically show a skipped count and, for each, the reason: your `@Disabled("...")` string, or for conditionals an auto-generated message like 'Disabled on OS: MAC' or 'Disabled because property did not match'. This is why the reason string matters - it is your audit trail. ## The scale problem: silent coverage erosion The insidious risk is that **a fully green build can hide a large and growing set of skipped tests**. Each `@Disabled` quietly subtracts coverage while the suite still reports success. Over time this produces *false confidence*: code paths appear tested but aren't. Symptoms include rising skipped counts, disabled tests with stale or missing reasons, and 'temporary' skips that have outlived the bug they were parked for. ## Mitigations - **Make disabling accountable.** Fail CI on a `@Disabled` lacking a reason or a tracking ticket (lint/static analysis). - **Surface the signal.** Track and trend the skipped count; treat a rising number as a quality regression, not noise. - **Audit and prune.** Periodically review disabled tests to re-enable, fix, or delete - a disabled test that will never run should be removed, not left to rot. - **Prefer conditionals for environmental gating** so tests self-enable where valid, instead of being globally off. - **For flaky tests, weigh alternatives.** *Quarantine* (keep running but don't fail the build, collecting flake data) preserves signal better than a blunt `@Disabled`; fixing the root cause is best of all. Disabling is the easiest and most forgettable option, which is exactly why it accumulates. ## Bottom line `@Disabled` is a correct, useful escape hatch, but it is *state* you are adding to the codebase. Treat each disabled test as a small, tracked, time-boxed debt with an owner and an exit condition - not a silent permanent off-switch.
- Do @BeforeEach methods run for a test that is disabled?No. JUnit decides the test is disabled before executing it, so its per-test setup/teardown don't run - there is nothing to prepare for a test that won't execute.
- What is a better option than @Disabled for a genuinely flaky test you don't want to fix right now?Quarantine it - keep running it but don't let it fail the build - so you still collect flake data, or invest in fixing the root cause. @Disabled removes all signal and is easy to forget.
saying these in an interview costs you the question
- Assuming a disabled test's @BeforeEach still seeds data for other tests
- Treating a green build as full coverage despite many skipped tests
- Counting skipped tests as passed in coverage/quality metrics
- Letting 'temporary' disables become permanent with no audit or ticket