Skip to main content

Glob Patterns

A glob pattern in @Gherkin2JUnit lets a single marker class drive many spec files — one generated test class per spec, all extending the same marker, even across sub-packages.

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

What this demonstrates​

  • @Gherkin2JUnit("./**/*.specb") matches every .specb file in the marker's package and every sub-package below it
  • ./ resolves against the marker's package, so the pattern doesn't repeat the package name
  • One marker class → one generated test class per discovered spec
  • All generated classes extend the same marker
  • Each generated class lands in its spec's own package (glob.cart, glob.user), next to the spec and its test

Directory layout​

The specs are co-located with the Java code, each in the sub-package it belongs to, with its concrete test beside it:

src/test/java/.../glob/
├── AllFeatures.java ← single marker class with the glob pattern
├── cart/
│ ├── AddToCart.specb
│ ├── AddToCartTest.java
│ ├── Checkout.specb
│ └── CheckoutTest.java
└── user/
├── Login.specb
├── LoginTest.java
├── Registration.specb
└── RegistrationTest.java

The marker class​

The marker needs nothing but the glob pattern:

@Gherkin2JUnit("./**/*.specb")
public abstract class AllFeatures {
}
Glob versus bare @Gherkin2JUnit

A bare @Gherkin2JUnit (no value) only looks for spec files in the marker's own package. The recursive ** is what reaches cart/ and user/. Without the ./ prefix, a pattern is resolved from the classpath root instead — e.g. @Gherkin2JUnit("specs/**/*.specb") for specs kept under src/test/resources/specs/.

What gets generated​

AllFeatures.java
├→ cart/AddToCartScenarios.java (from cart/AddToCart.specb)
│ └→ cart/AddToCartTest.java (concrete)
├→ cart/CheckoutScenarios.java (from cart/Checkout.specb)
│ └→ cart/CheckoutTest.java (concrete)
├→ user/LoginScenarios.java (from user/Login.specb)
│ └→ user/LoginTest.java (concrete)
└→ user/RegistrationScenarios.java (from user/Registration.specb)
└→ user/RegistrationTest.java (concrete)

Each generated class is independent and extends AllFeatures.

Implementing the steps​

Each spec gets its own concrete test class next to it, implementing that spec's steps. Some steps appear in more than one spec — I have an empty shopping cart, I should see "…" — and each generated class declares them separately, so each test implements its own copy. To share them instead, see Sharing Steps via a Base Class or Organizing Steps into Interfaces.

Run it​

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