Execution Reporter
The dev.specbinder:execution-reporter module is a JUnit 5 extension that writes one JSON file per feature to the project's build output directory. You opt a feature in by annotating its marker class with @ExtendWith(SpecBinderReporter.class). Useful for CI dashboards, custom reporting, or any tooling that needs structured spec-execution data.
Source: examples/going-further/example-4 on GitHub.
What this demonstrates
- Activated explicitly per feature with
@ExtendWith(SpecBinderReporter.class)on the marker class - Each feature gets its own JSON report under
target/specbinder-reports/... - The report mirrors the Gherkin hierarchy:
feature → rules → scenarios → outlines → examples - Pass / fail / aborted statuses for every node, with full error blocks for failures
- Non-SpecBinder tests are silently ignored
- Two generation options enrich the report:
emitScenarioHash(verbatim step text + typed arguments) anddescriptionAsAnnotation(Gherkin descriptions in the JSON)
Activation
Add the dependency:
<dependency>
<groupId>dev.specbinder</groupId>
<artifactId>execution-reporter</artifactId>
<version>2026.38.0</version>
<scope>test</scope>
</dependency>
Then activate the reporter by annotating the marker class with @ExtendWith(SpecBinderReporter.class):
@Gherkin2JUnit("specs/ShoppingCart.feature")
@ExtendWith(SpecBinderReporter.class)
public abstract class ShoppingCartFeature { … }
Because JUnit's @ExtendWith is @Inherited, placing it on the abstract marker means every generated …Scenarios subclass that JUnit runs inherits it — so a single annotation covers the whole feature. Only classes carrying the extension produce a report; every other test is left untouched.
Running it
cd examples/going-further/example-4
mvn test
After the run, look at:
target/specbinder-reports/specs/ShoppingCart.feature.json
Report schema
The schema is hierarchical and uses the same displayName field name at every node:
feature
├── scenarios[] ← plain scenarios + Scenario Outlines under the feature
└── rules[]
└── scenarios[] ← scenarios that live under a Rule
The example feature deliberately exercises every code path the listener handles:
- Several plain scenarios that pass (real assertions against an in-memory cart)
- One scenario with a wrong expected total →
status: "failed", populatederrorblock - One scenario whose
GivencallsAssumptions.abort(...)→status: "aborted" - A
Rulewith two scenarios → routed under the report'srules[]branch - A
Scenario Outlinewith three rows → ascenarioOutlinenode with threeexamples[]entries
Enriching the report
Two @Gherkin2JUnitOptions flags on the marker class make the JSON report carry more than just statuses and timings:
@Gherkin2JUnit("specs/ShoppingCart.feature")
@Gherkin2JUnitOptions(emitScenarioHash = true, descriptionAsAnnotation = true)
@ExtendWith(SpecBinderReporter.class)
public abstract class ShoppingCartFeature { … }
emitScenarioHash = truestamps each generated scenario method with a@ScenarioHash— a content hash of its executable steps. Downstream tooling can compare it against live source to detect when a scenario has drifted since the recorded run. It also unlocks the report's verbatim Gherkin steptextand typedargumentsfor each step (both gated on the hash still matching the source.feature).descriptionAsAnnotation = trueemits Gherkin description text — under the Feature, Rule, or Scenario — as runtime-retained@Descriptionannotations instead of JavaDoc. The reporter reads them via reflection and adds adescriptionfield at each level of the JSON. This feature'sFeature:andRule:blocks both carry a description, so the report shows one at both levels.
Both default to false; the reporter simply omits the corresponding fields when they're off.