Skip to main content

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​

  • Rule blocks become @Nested inner classes
  • Each Rule gets a @DisplayName with the rule title
  • Scenarios inside a Rule become @Test methods on the nested class
  • Scenarios outside any Rule remain at the top level
  • Rule description lines become JavaDoc on the nested class
  • @Order annotations preserve feature-file ordering
  • Step methods are implemented once in a concrete subclass; the @Nested rule 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​

GherkinJUnit
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 descriptionJavaDoc 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