Gherkin → JUnit 5 Mapping
A reference table for what each Gherkin construct becomes in the generated JUnit 5 code. For runnable examples of each pattern, see the Examples section.
The defaults below assume abstract mode (shouldBeAbstract = true) — the generated class is named <Marker>Scenarios, every previously-unimplemented step is declared abstract, and you create a concrete subclass that overrides the abstract methods. In concrete mode (shouldBeAbstract = false) the generated class is named <Marker>Test, abstract declarations are replaced with bodies (see unimplementedStepBehavior), and the class is itself runnable.
Primary keywords
| Gherkin | JUnit 5 output |
|---|---|
Feature: Foo | public abstract class FooScenarios extends FooFeature with @DisplayName("Foo") |
Feature description (free text under Feature:) | JavaDoc on the generated class |
Background: (feature-level) | @BeforeEach public void featureBackground(TestInfo testInfo) { … } on the outer class |
Background: (rule-level) | @BeforeEach public void ruleBackground(TestInfo testInfo) { … } on the @Nested rule class |
Rule: R1 | @Nested @DisplayName("Rule: R1") public class Rule_N { … } |
| Rule description | JavaDoc on the nested class |
Scenario: S1 (top level) | @Test @DisplayName("Scenario: S1") public void scenario_N() |
Scenario: S1 (inside a Rule) | @Test @DisplayName("Scenario: S1") public void scenario_N() on the nested class |
Scenario Outline: … + Examples: | @ParameterizedTest with one @CsvSource(textBlock = …) per Examples block |
Examples: row | One iteration of the parameterized test |
Secondary keywords
| Gherkin | JUnit 5 output |
|---|---|
Given <text> | Abstract / inherited / annotated method call inside the @Test method |
When <text> | Same — keyword does not change the method signature (unless useStepKeywordInStepMethodName = true) |
Then <text> | Same |
And <text> / But <text> | Same — inherits the keyword of the preceding Given / When / Then |
Step "quoted" argument | String / Integer / Long / Double / Boolean / Character parameter (type inferred), with $p1, $p2, … slot in the method name |
Step <placeholder> (Scenario Outline) | Parameter from the Examples table — column header → parameter name, value → inferred type |
Step <DocString> (triple-quoted) | Trailing String parameter, value emitted as a Java text block |
Step <DataTable> | List<XxxParam> (default), List<Map<String, String>>, or io.cucumber.datatable.DataTable — see Data Tables |
Tags
| Gherkin | JUnit 5 output |
|---|---|
@smoke on a Feature | @Tag("smoke") on the generated outer class |
@smoke @regression on a Feature | @Tags({@Tag("smoke"), @Tag("regression")}) |
@ui on a Rule | @Tag("ui") on the nested rule class |
@happy-path on a Scenario | @Tag("happy-path") on the @Test method |
Comments and ordering
| Gherkin | JUnit 5 output |
|---|---|
| Original step text | Preserved verbatim as a block comment above the step call: /* Given user exists */ |
| Feature-file order | Preserved using @Order(N) annotations on rules and scenarios |
Line numbers (when addSourceLineNumbers = true) | Embedded in @DisplayName and step block comments — e.g. @DisplayName("Scenario [12]: …") and /* [13] Given user exists */ |
Empty / incomplete elements
| Gherkin | JUnit 5 output |
|---|---|
Rule: with no scenarios | A failing @Test public void noScenariosInRule() on the nested class, tagged @new by default (see tagForEmptyRules) |
Scenario: with no steps | A failing @Test calling Assertions.fail("Scenario has no steps"), tagged @new by default |
Behaviour is configurable via emptyRuleBehavior and emptyScenarioBehavior:
FAIL(default) — emit a failing assertionSKIP— emit anAssumptions.assumeTrue(false, …)so the test is reported as abortedCOMPILATION_ERROR— emit a non-Java token so the project will not compile
See Configuration → Empty Gherkin elements for full details.
Step name derivation
The same Gherkin step under different keywords reuses the same method (unless useStepKeywordInStepMethodName = true):
| Step text | Generated method name |
|---|---|
Given user exists | userExists() |
When user exists | userExists() — same method |
Then "alice" is signed in | $p1IsSignedIn(String p1) |
Then "alice" has "3" items | $p1Has$p2Items(String p1, Integer p2) |
Given my cart contains the following products: (with a data table) | myCartContainsTheFollowingProducts(List<ProductsParam> products) |
Marker class lookup
For every step the generator processes, it first searches the marker class hierarchy for an existing implementation:
- By method name — derived as above
- By annotation pattern (Cucumber
@Given/@When/@Thenannotations on parent methods) — whenuseCucumberAnnotationsForStepMatching = true, which is turned on by default for backward compatibility when migration from cucumber based projects
If a match is found, no abstract declaration (or stub) is emitted for that step. The generated @Test method simply calls the inherited implementation.
See also
- Configuration — every
@Gherkin2JUnitOptionsflag that influences the mappings above. - Examples — a runnable Maven project per mapping pattern.