Implementing Steps
A fully working example — you extend the generated abstract class in a concrete subclass, implement each step method with real assertions, and the tests run green.
Source: examples/getting-started/example-3 on GitHub.
What this demonstrates
- The end-to-end workflow from spec file to passing tests
- The default abstract mode: the generated
…Scenariosclass isabstract, and you implement its step methods in a concrete subclass - State management via plain instance fields on the subclass — no DI framework needed
- Real JUnit assertions in step methods
- Any step method you forget to implement is a compile error, not a runtime failure
The workflow
- Create a marker class annotated with
@Gherkin2JUnit("…"). - Compile — the generator emits an abstract class
…Scenarioswith one abstract method per step and one@Testmethod per scenario. - Create a concrete subclass that extends the generated
…Scenariosclass and implement every abstract step method — this is where your real test code and shared state live. - JUnit discovers and runs the concrete subclass; any unimplemented step won't compile.
Steps shared across many features can instead be implemented on the marker class itself — the generator inherits them and skips the abstract declaration. To make the generated class runnable without a subclass, see Concrete Mode.
Implementing the steps
The concrete subclass extends the generated class and holds shared state in plain instance fields:
public class ShoppingCartTest extends ShoppingCartScenarios {
private final List<CartItem> cart = new ArrayList<>();
@Override
public void iHaveAnEmptyShoppingCart() {
cart.clear();
}
@Override
public void iAdd$p1WithQuantity$p2AndUnitPrice$p3(String name, Integer quantity, Double unitPrice) {
cart.add(new CartItem(name, quantity, unitPrice));
}
@Override
public void theCartSubtotalShouldBe$p1(Double expectedSubtotal) {
double subtotal = cart.stream()
.mapToDouble(item -> item.quantity() * item.unitPrice())
.sum();
assertEquals(expectedSubtotal, subtotal, 0.001);
}
record CartItem(String name, int quantity, double unitPrice) {}
}
Parameter names in your implementation can be anything — only the method name and parameter types need to match the generated signature.
Run it
cd examples/getting-started/example-3
mvn test