Rules
Gherkin Rule blocks group related scenarios under a business rule. They map to JUnit @Nested test classes.
Source: examples/getting-started/example-4 on GitHub.
What this demonstrates
Ruleblocks become@Nestedinner classes- Each
Rulegets a@DisplayNamewith the rule title - Scenarios inside a
Rulebecome@Testmethods on the nested class - Scenarios outside any
Ruleremain at the top level - Rule description lines become JavaDoc on the nested class
@Orderannotations preserve feature-file ordering- Step methods are implemented once in a concrete subclass; the
@Nestedrule classes call the same implementations on the outer instance, so top-level and rule scenarios share one set of steps and state
Gherkin → JUnit mapping
| Gherkin | JUnit |
|---|---|
Feature: | Outer test class |
Scenario: (top level) | @Test method on outer class |
Rule: | @Nested inner class |
Scenario: (inside Rule) | @Test method on nested class |
| Rule title | @DisplayName on nested class |
| Rule description | JavaDoc on nested class |
Generated structure
public abstract class ShoppingCartScenarios extends ShoppingCartFeature {
@Test
@DisplayName("Scenario: View an empty cart")
public void scenario_1() { /* ... */ }
@Nested
@DisplayName("Rule: Free shipping applies to orders over 50 euros")
public class Rule_1 {
@Test
@DisplayName("Scenario: Show free shipping when threshold is met")
public void rule_1_scenario_1() { /* ... */ }
@Test
@DisplayName("Scenario: Show shipping cost when below threshold")
public void rule_1_scenario_2() { /* ... */ }
}
@Nested
@DisplayName("Rule: Discount codes apply a percentage reduction")
public class Rule_2 {
@Test
@DisplayName("Scenario: Apply a valid discount code")
public void rule_2_scenario_1() { /* ... */ }
@Test
@DisplayName("Scenario: Reject an expired discount code")
public void rule_2_scenario_2() { /* ... */ }
}
}
The test class
The nested rule classes are inner classes of the generated ShoppingCartScenarios, so their scenarios call the step
methods of the outer instance. One concrete subclass implements every step — whether a top-level scenario or a rule
scenario uses it:
ShoppingCartTest.java
public class ShoppingCartTest extends ShoppingCartScenarios {
private double subtotal;
private String banner;
@Override
public void myCartSubtotalIs$p1(Double amount) {
subtotal = amount;
}
@Override
public void iShouldSeeThe$p1Banner(String expectedBanner) {
assertEquals(expectedBanner, banner);
}
// ... the remaining steps, for both rules and the top-level scenario
}
ShoppingCartFeature.java (marker class, @Gherkin2JUnit)
└→ ShoppingCartScenarios.java (generated, abstract — @Test methods and @Nested rule classes)
└→ ShoppingCartTest.java (your concrete class, implements the step methods)
Run it
cd examples/getting-started/example-4
mvn test