Abstract Mode
Abstract mode is the default — the generator emits an abstract test class with one abstract method per step. Missing implementations are caught at compile time, not at run time.
Source: examples/common-use-cases/example-4 on GitHub.
What this demonstrates
- The three-layer class hierarchy: marker → generated abstract → concrete test
- All step methods declared
abstract— no failing stubs - Methods already implemented on the marker class are inherited and not re-declared
- Missing
@Overridemethods cause a compiler error, not a runtime failure - How to opt out via
@Gherkin2JUnitOptions(shouldBeAbstract = false)
The class hierarchy
ShoppingCartFeature.java (marker class, @Gherkin2JUnit)
└→ ShoppingCartScenarios.java (generated, abstract, contains @Test methods)
└→ ShoppingCartTest.java (your concrete class, implements step methods)
Inherited vs. abstract step methods
In the marker class:
public abstract class ShoppingCartFeature {
public void myCartSubtotalIs$p1(Double amount) { /* implemented here */ }
public void iViewTheCart() { /* implemented here */ }
}
In the generated ShoppingCartScenarios:
myCartSubtotalIs$p1()— inherited, not re-declarediViewTheCart()— inherited, not re-declarediHaveAnEmptyShoppingCart()— abstract, must be implemented inShoppingCartTestiAdd$p1WithQuantity$p2AndUnitPrice$p3()— abstracttheCartShouldContain$p1Item()— abstract
Abstract vs. concrete mode
| Aspect | Abstract (default) | Concrete |
|---|---|---|
| Generated class | abstract, extends marker | Concrete, extends marker |
| New step methods | abstract declarations | Failing stubs (Assertions.fail(...)) |
| Inherited step methods | Not re-declared | Not re-declared |
| Missing implementations | Compile error | Runtime failure |
| Where you implement | Marker class or concrete subclass | Marker class |
| Class suffix | Scenarios | Test |
| Opt in via | (default) | @Gherkin2JUnitOptions(shouldBeAbstract = false) |
In both modes, methods already present on the marker class are inherited — the generator doesn't emit stubs or abstract declarations for them. The difference is only in how new (unimplemented) steps are handled.
Run it
cd examples/common-use-cases/example-4
mvn test