Skip to main content

Config Inheritance

Share generation options across many marker classes via @Gherkin2JUnitOptions on a base class. Override specific options per marker as needed.

Source: examples/common-use-cases/example-7 on GitHub.

What this demonstrates​

  • @Gherkin2JUnitOptions on a base class applies to every marker class that extends it
  • The annotation is @Inherited — child classes pick up all options automatically
  • A child class with its own @Gherkin2JUnitOptions overrides only the options it explicitly sets — unspecified options keep their inherited value
  • One base class can standardise generation behaviour across a whole project
  • Both effects show up in the concrete tests: the class they extend and the step method names they implement

Directory layout​

The shared base class sits at the top; each feature gets its own sub-package holding its marker, spec and test, so the package structure mirrors the inheritance hierarchy:

src/test/java/.../optionsinheritance/
├── BaseFeature.java ← shared @Gherkin2JUnitOptions
├── shoppingcart/
│ ├── ShoppingCartFeature.java ← marker, inherits all options
│ ├── ShoppingCart.specb
│ └── ShoppingCartTest.java
└── checkout/
├── CheckoutFeature.java ← marker, overrides one option
├── Checkout.specb
└── CheckoutTest.java

With one spec per sub-package, both markers use a bare @Gherkin2JUnit and discover their spec by convention.

Class hierarchy​

BaseFeature.java                     (@Gherkin2JUnitOptions — shared options)
├── ShoppingCartFeature.java (inherits all options)
│ └→ ShoppingCartSpec.java (generated, abstract — "Spec" suffix, keyword-prefixed steps)
│ └→ ShoppingCartTest.java
└── CheckoutFeature.java (@Gherkin2JUnitOptions — overrides useStepKeywordInStepMethodName)
└→ CheckoutSpec.java (generated, abstract — "Spec" suffix, plain step names)
└→ CheckoutTest.java

How options flow​

@Gherkin2JUnitOptions(
useStepKeywordInStepMethodName = true,
classSuffixIfAbstract = "Spec"
)
public abstract class BaseFeature {
}

// in shoppingcart/
@Gherkin2JUnit
public abstract class ShoppingCartFeature extends BaseFeature {
// Inherits everything from BaseFeature
}

// in checkout/
@Gherkin2JUnitOptions(useStepKeywordInStepMethodName = false) // only this is locally set
@Gherkin2JUnit
public abstract class CheckoutFeature extends BaseFeature {
// Still inherits classSuffixIfAbstract = "Spec"
}
OptionBaseFeatureShoppingCartFeatureCheckoutFeature
useStepKeywordInStepMethodNametrueinherited (true)overridden (false)
classSuffixIfAbstract"Spec"inherited ("Spec")inherited ("Spec")

Options are inherited along the class hierarchy, not the package structure — the markers live in sub-packages and still pick up everything from BaseFeature.

Effect on the generated code​

// ShoppingCartSpec — inherits both options: "Spec" suffix, keyword-prefixed step methods
public abstract class ShoppingCartSpec extends ShoppingCartFeature {
public abstract void givenIHaveAnEmptyShoppingCart();
public abstract void whenIAdd$p1ToTheCart(String p1);
public abstract void thenTheCartShouldContain$p1Item(Integer p1);
}

// CheckoutSpec — overrides the keyword option, still inherits the suffix
public abstract class CheckoutSpec extends CheckoutFeature {
public abstract void iHaveACartWith$p1Items(Integer p1);
public abstract void iProceedToCheckout();
public abstract void iPayWithCard$p1(Long p1);
public abstract void theOrderShouldBeConfirmed();
}

The concrete ShoppingCartTest and CheckoutTest extend ShoppingCartSpec and CheckoutSpec and implement those methods under exactly these names.

Run it​

cd examples/common-use-cases/example-7
mvn test