skip to content

In Cucumber, how do undefined, ambiguous and pending step results differ, and which one prints a snippet?

level: middleimportance: should knowfreq 58%

answer

  1. none matched, several matched, or unfinished
  2. only one of them offers you a stub
  3. the scenario stops either way
  4. duplicate patterns fail earlier than ambiguity

basics

~20 s

Undefined means no step definition matched the line, and Cucumber prints a snippet stub for it. Ambiguous means more than one matched, so the runner refuses to choose. Pending means a matched definition signalled unfinished work. All three stop the scenario.

solid answer

~40 s

All three say the binding is wrong rather than the assertion. **Undefined**: no pattern matched the Gherkin line, so Cucumber runs nothing and prints a **snippet** — a stub for that sentence, with literal numbers generalised into placeholders and a body that throws a pending exception. **Ambiguous**: two patterns both matched, so the runner reports the step as ambiguous and names the definitions it could not choose between; the identical-pattern case is caught earlier still, as a duplicate registration when the glue loads. **Pending**: a definition matched and deliberately signalled unfinished work — `PendingException` in Cucumber-JVM, a step returning `'pending'` in cucumber-js. In all three cases the scenario's remaining steps are skipped, and by default the run exits non-zero.

code

java · 5 lines
java
@When("the planner reassigns {int} technicians to turbine T-{int}")
public void the_planner_reassigns_technicians_to_turbine_t(Integer int1, Integer int2) {
    // Write code here that turns the phrase above into concrete actions
    throw new io.cucumber.java.PendingException();
}

go deeper

for a junior

Learn to read the three words in the run output: nothing matched the line, several things matched it, or matched code reported itself unfinished. Know that only the first prints a stub for you.

for a middle

Explain the mechanics: which result skips the rest of the scenario, how the snippet generalises literal values into placeholders, and how a pending exception differs from an assertion failure.

for a senior

Diagnose from the pattern of results — wholesale undefined steps point at support code that was never loaded, scattered ones at reworded Gherkin, ambiguous ones at a pattern with too much reach.

for a principal

Decide what these results mean for the pipeline: strict handling so unimplemented work cannot report green, and a review norm that stops one snippet per sentence becoming the suite's growth model.

## Four ways a step can end without passing When Cucumber executes a scenario it records a **result** for every step, and three of those results describe a binding problem rather than an assertion failure. Knowing which one you are looking at tells you where the fault is before you open any code. | Result | What it means | What caused it | |---|---|---| | **undefined** | no step definition matched the line | the definition does not exist, or its pattern does not cover this wording | | **ambiguous** | more than one definition matched the line | two patterns both claim the sentence; the runner refuses to choose | | **pending** | a definition matched and signalled unfinished work | the glue deliberately reported itself as not implemented | | **skipped** | the step never ran | an earlier step in the scenario did not pass | **failed** is the fifth, and it is the ordinary one: the definition ran and threw. The three above are distinct from it precisely because no test logic executed. ## Undefined, and the snippet When no pattern matches, Cucumber cannot run anything, so it reports the step as **undefined** and prints a **snippet**: a ready-made step-definition stub for that exact sentence. The snippet is a convenience with three useful properties and one trap. - It generalises literal values into placeholders, so a line mentioning a turbine number comes back with `{int}` where the digits were, and a matching method parameter. - Its shape follows the snippet style configured for the run — Cucumber-JVM exposes a `cucumber.snippet-type` setting whose values are `underscore` and `camelcase`, which only affects the generated method name. - Its body throws a pending exception rather than doing nothing, so a pasted-but-unfinished step announces itself instead of passing silently. The trap: the snippet is generated from **one** sentence. Pasting it verbatim for every undefined line is how a suite grows one definition per sentence. Treat it as a starting point — widen the pattern, merge it with a definition that nearly matched, or fix the Gherkin wording that made it not match. ## Ambiguous, and its load-time cousin **Ambiguous** is a run-time result: two different patterns both matched one line, so the runner reports the step as ambiguous and names the definitions it could not choose between. That naming is the whole diagnostic — it points at both patterns, and the fix is to narrow one of them or to reword the step. Distinguish it from the load-time case: two step definitions carrying the *identical* pattern are a duplicate registration, and Cucumber-JVM rejects that when it loads the glue, before any scenario runs. Same underlying mistake, two very different moments and messages. On a 63-scenario wind-farm maintenance planner feature set that two teams both edit, ambiguity is nearly always the product of reach: an unanchored or heavily alternated pattern written by one team also covers a sentence the other team defined. The result is a safety feature — running the wrong glue silently would be far worse. ## Pending **Pending** means a definition matched, ran, and reported that the work is not finished. It is deliberate, and each implementation spells it differently: in Cucumber-JVM the glue throws `PendingException` — which is exactly what a generated snippet does — and in cucumber-js a step function returns the string `'pending'`. The remaining steps of that scenario are then skipped, because continuing past unimplemented behaviour would test nothing. ## What the run does with all three 1. **The scenario stops.** Undefined, ambiguous and pending all halt that scenario; the steps after the offending one are recorded as skipped. 2. **The run fails.** Cucumber's default is strict, so a run containing undefined or pending steps exits non-zero even though no assertion failed. That default is what stops a half-written suite from reporting green in CI. 3. **The report keeps the distinction.** Because the statuses are separate values, a report can tell you how much of the suite is unimplemented versus how much is genuinely broken — a much more useful signal than a single failure count. Read a red run in that order: ambiguous means fix a pattern, undefined means write or widen a definition, pending means finish the work, failed means the code under test or the assertion is wrong.

  • Why does a generated snippet throw rather than leave an empty body?
    So a pasted stub cannot pass. An empty method would report the step as passed, and a scenario full of empty stubs would go green while testing nothing. Throwing the pending exception marks the step pending, skips the rest of the scenario and, with the default strict handling, fails the run — which keeps unimplemented work visible in CI instead of hiding it behind a green suite.
  • Two definitions with the identical pattern versus two different patterns that both match — do those fail the same way?
    No. Identical patterns are a duplicate registration and Cucumber-JVM rejects them as the glue loads, before any scenario runs. Two different patterns that happen to cover one sentence can only be detected when that sentence executes, so it surfaces per step as an ambiguous result naming both definitions. Same underlying mistake, different moment and different message.
  • A run reports 40 undefined steps after a merge. Where do you look first?
    At whether the glue was loaded at all. Wholesale undefined steps usually mean the support code was not on the path the runner scans, not that 40 definitions vanished — a build or packaging change is the usual cause. Scattered undefined steps are the opposite case: individual sentences reworded in the feature files so they no longer match the patterns that used to cover them.

saying these in an interview costs you the question

  • Uses undefined and failed interchangeably when reading a report
  • Thinks an ambiguous step means the step text was misspelled
  • Pastes a generated snippet per sentence without merging definitions
  • Assumes undefined or pending steps still let the run exit zero
  • Believes the steps after an undefined one still execute