Skip to main content

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 @Override methods 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-declared
  • iViewTheCart()inherited, not re-declared
  • iHaveAnEmptyShoppingCart()abstract, must be implemented in ShoppingCartTest
  • iAdd$p1WithQuantity$p2AndUnitPrice$p3()abstract
  • theCartShouldContain$p1Item()abstract

Abstract vs. concrete mode

AspectAbstract (default)Concrete
Generated classabstract, extends markerConcrete, extends marker
New step methodsabstract declarationsFailing stubs (Assertions.fail(...))
Inherited step methodsNot re-declaredNot re-declared
Missing implementationsCompile errorRuntime failure
Where you implementMarker class or concrete subclassMarker class
Class suffixScenariosTest
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