cswork / libraryOpen practice workspace

Articles

Cucumber Interview Questions for SDETs: Hooks, Scenario State, and Isolation

Practice Cucumber-JVM interview questions on hooks, scenario state, Background order, failed steps, tags, outlines, and parallel isolation.

Experienced Cucumber interviews rarely stop at defining Given, When, and Then. The difficult questions ask why a scenario passes alone but fails in the suite, which cleanup still runs after an assertion fails, and whether a hook or a Background owns setup.

Quick answer: treat every scenario as an independent test with its own mutable state, data, and cleanup. In Cucumber-JVM, ordinary glue objects are created for each scenario, but static fields, singletons, shared databases, and reused browser sessions can cross that boundary. Trace the lifecycle as Before hooks → Background steps → scenario steps → After hooks. If a step fails, later steps are skipped, but the matching AfterStep and scenario-level After hooks still run.

This guide separates official Cucumber behavior from our executable lab results and editorial interview guidance. It does not claim that a named employer asks these exact questions.

What state belongs to a single scenario?

Interview question: Why should scenarios never share state?

Official behavior: Cucumber's state guide says scenarios must be independent and specifically warns against global or static variables. For JVM bindings, Cucumber creates a new instance of each glue class before each scenario. That makes an ordinary instance field suitable for state shared between steps in one scenario. It does not make a static field safe. Cucumber state documentation.

A strong answer names the ownership boundary. A cart, authenticated user, response, or page object may live for one scenario. A test-run reporter or immutable configuration may live longer. A mutable singleton, shared account, database row with a fixed key, or browser cookie jar can leak results into the next scenario.

Do not say that an After hook creates independence by itself. Cleanup can fail, and an abrupt process exit can prevent it. Prefer unique scenario data and fresh scoped objects, then add idempotent cleanup for external resources. If two workers can use the same customer ID, deleting it afterward does not prevent the collision that occurred during the test.

The minimal static-state reproduction

Our lab pins Cucumber-JVM 7.34.8 on JDK 21. Both scenarios increment the same deliberately incorrect field:

private static int sharedCounter = 0;

@When("this scenario increments the shared counter")
public void incrementCounter() {
    sharedCounter++;
}

@Then("the counter visible to this scenario is one")
public void counterShouldBeOne() {
    assertEquals(1, sharedCounter);
}

Each scenario passes when it starts from a fresh JVM. In one suite, the runner records:

Scenario: First order starts at one
TRACE before-2 sharedCounter remains=0
TRACE action-step sharedCounter=1
TRACE assertion-step expected=1 actual=1

Scenario: Second order also starts at one
TRACE before-2 sharedCounter remains=1
TRACE action-step sharedCounter=2
TRACE assertion-step expected=1 actual=2
Tests run: 2, Failures: 1

That pair is more useful than rerunning the failing scenario until it passes. It identifies order-dependent state and shows the value that crossed the scenario boundary.

How would you repair the leak?

The lab's teaching repair resets the counter in a Before hook, and both scenarios pass. In production test code, the better repair is usually to remove static mutation and put state in a scenario-scoped object. Cucumber recommends PicoContainer when a JVM application has no existing dependency-injection module; Spring and Guice also have scenario scopes. Cucumber-JVM installation guidance.

Explain the trade-off: a reset hook is a useful containment step and proves the diagnosis, while scenario-scoped construction makes invalid sharing harder to introduce. External systems still require separate data keys and cleanup.

How do hooks, Background, and steps run together?

Interview question: Does Background run once for the feature?

No. Official Gherkin behavior: Background steps run before each scenario, after any Before hooks. A feature or rule can have one Background at its level. It supplies readable business context; it is not a one-time fixture. Gherkin reference.

Our passing run recorded this sequence for both scenarios:

Observed orderRunner eventPractical owner
1before-1 allocate scenario objectScenario-scoped test context
2before-2 reset sharedCounter=0Technical setup or containment
3before-step → background-step → after-stepBusiness-readable common context
4before-step → action step → after-stepScenario behavior
5before-step → assertion step → after-stepObservable outcome
6after-2 captureEvidence before destructive cleanup
7after-1 releaseResource cleanup

The numeric hook orders are intentional. The run shows Before(order=1) before Before(order=2), while After(order=2) executes before After(order=1). Use ordering sparingly. If hook B silently relies on hook A, give their responsibilities clear names and consider combining them in one fixture owner.

When should setup be a Background rather than a hook?

Use a Background when the condition matters to the person reading the business example: “Given the account has an active subscription.” Use a hook for technical mechanics such as starting a transaction, allocating an isolated namespace, or attaching a failure artifact.

Avoid hiding essential business preconditions inside hooks. A scenario that reads “When checkout is submitted” is ambiguous if a hook secretly creates a paid cart, inventory, and promotion. Conversely, a five-step browser-and-database ritual in every Background overwhelms the behavior. Express the meaningful condition in Gherkin and let its step definition delegate technical setup.

What happens after a step fails?

Interview question: Will cleanup run after an assertion failure?

Official API behavior: After hooks run after the last attempted step even when the result is failed, undefined, pending, or skipped. Step hooks have around semantics: when BeforeStep ran, the matching AfterStep runs regardless of that step's result. Following steps and their hooks are skipped after a non-passing step. Cucumber API reference.

Our deliberately failing scenario produced:

TRACE before-step
TRACE failing-step throws AssertionError
TRACE after-step
TRACE after-2 capture sharedCounter=0
TRACE after-1 release scenario resources
Tests run: 1, Failures: 1

The later step did not print its marker. This trace supports a practical pattern: capture screenshots, logs, response bodies, or identifiers before cleanup destroys the evidence; then release resources in a lower-order After hook. Make cleanup idempotent so a partially completed scenario does not create a second failure that hides the first.

Do not promise that cleanup always completes. A killed JVM, worker crash, or machine loss can bypass in-process hooks. External test data may need TTLs, unique run identifiers, or a separate janitor job.

Why does a scenario pass alone but fail in the suite?

Interview question: How would you debug an order-dependent Cucumber test?

Start with observations rather than a timeout increase:

  1. Run the failing scenario alone with the same configuration.
  2. Run the smallest failing pair in both orders.
  3. Log scenario IDs, worker IDs, data keys, hook entry and exit, and the first unexpected value.
  4. Inventory mutable state: static fields, DI scopes, caches, environment variables, clocks, ports, database rows, queues, cookies, and mocks.
  5. Make one ownership change, then repeat the pair and the full suite.

If the failure appears only in parallel, force the suspected collision with two scenarios that use the same resource. Scenario-scoped Java objects do not isolate a shared database, file, port, or remote account. Allocate unique data per scenario and make assertions about the scenario's own resource.

Retries can reveal frequency and preserve more evidence, but a passing retry is not a repair. Fixed scenario ordering is also not a repair; it turns a hidden dependency into suite policy.

What should a senior answer say about parallel execution?

Separate memory isolation from resource isolation. New glue instances protect ordinary instance fields. Thread-safe collections only prevent memory corruption; they do not make shared business state semantically independent. Two scenarios can safely increment a concurrent map and still invalidate each other's expected totals.

State the runner and configuration you actually use. Cucumber supports several engines and build tools, and their parallel controls differ. The invariant is stable: every scenario must remain correct when selected alone, reordered, or assigned to another worker, unless the test explicitly represents coordinated multi-actor behavior.

How do tags and Scenario Outlines change execution?

Interview question: Do tags provide isolation?

Tags select scenarios and conditionally apply hooks; they do not reset state. A tag expression such as @smoke and not @slow changes which pickles execute. If selecting @state makes a suite pass, that may simply remove the scenario that contaminated it.

Use conditional hooks when a capability truly requires specialized setup, such as @browser or @database. Avoid making tag names encode an undocumented hook dependency. A reader should be able to understand why the setup applies.

How does a Scenario Outline affect lifecycle?

Official Gherkin behavior: a Scenario Outline is a template and runs once for every data row in its Examples section. Parameters are substituted before step matching. Each row is therefore a separate scenario execution with its own hooks and Background. Gherkin reference.

That distinction matters for data. Store row-specific results in scenario state, not in a collection that survives all examples. If ten example rows leave ten customers behind, use unique identifiers plus cleanup; do not assume the outline is one scenario with one teardown.

Cucumber-JVM interview questions with concise answers

What is the safest way to share state between step classes?

Use a scenario-scoped context supplied through dependency injection. Cucumber's JVM guidance recommends PicoContainer when the application has no existing DI choice. Pass the context explicitly and keep mutable values out of static fields.

Should every setup action go in a Before hook?

No. Put readable business preconditions in scenario or Background steps. Reserve hooks for cross-cutting mechanics whose details would distract from the behavior, such as allocating isolated infrastructure or collecting diagnostics.

Why can an After hook make debugging harder?

Destructive cleanup can erase the state that explains the first failure, and cleanup exceptions can add noise. Capture evidence first, preserve the original error, then clean up idempotently.

Is hook order a good dependency system?

It is a sequencing mechanism, not a substitute for clear ownership. Use explicit order where capture must precede cleanup. Avoid long chains in which hooks depend on invisible side effects.

What would you verify before changing a flaky scenario?

Verify the exact runner, binding version, tag filter, seed or order, worker count, test data, and first failed assertion. Then reproduce the smallest interfering pair.

Sources and Further Reading