Skip to main content

Why compile-time Gherkin?

BDD makes a promise that almost everybody likes: readable specifications that double as executable tests.

Write the behaviour in Gherkin. Run it as a test suite. Ship with confidence.

The promise is real. The tooling that delivers it — Cucumber, JBehave, SpecFlow, Reqnroll, Behave, and friends — is also real, mature, and battle-tested. SpecBinder is not here to argue with any of that.

It is here to argue with a few specific choices that most runtime Gherkin tools share, and that start to hurt as a test suite grows.

The recurring pain​

Most Gherkin runners follow the same recipe:

  1. Parse .feature files at runtime.
  2. Scan the classpath for step definitions tagged with @Given / @When / @Then.
  3. Match each step text against a regex or expression.
  4. Inject shared state through a DI container.
  5. Hand the whole thing to a custom test runner.

It works. It also produces a familiar set of complaints once a project grows past a few hundred scenarios:

  • Undefined steps are runtime surprises. You only learn that a step has no match when the test runs.
  • Ambiguous matches are worse surprises. Two regexes claim the same step, and your test silently runs the wrong code.
  • The global step registry is a free-for-all. Every step definition is visible to every feature. Renaming one phrase can ripple across modules you've never opened.
  • State is awkward. PicoContainer, Spring, Guice, or a hand-rolled ScenarioContext — pick your poison.
  • Data tables are stringly typed. row.get("price") returns a String. You parse, you cast, you hope.
  • IDE support is second-class. Find Usages, Rename, navigation — they all work almost as well as for plain Java. Almost.

These are not new observations.

Anyone who has shipped a large Cucumber-style suite has probably met at least three of them.

Possibly before coffee.

A different recipe​

SpecBinder picks a single, opinionated swap: do all of that at compile time, not runtime.

A Java annotation processor reads your .feature or .specb files during javac and emits a plain JUnit 5 test class for each one. Every Given/When/Then becomes a strongly-named, statically-bound method call. No runner, no classpath scan, no regex matcher, no DI container..

The result is Gherkin automation that behaves much more like ordinary Java test code: visible to the compiler, navigable in the IDE, and executable by standard JUnit tooling.

What this section covers​

The pages in this section walk through the main ideas one by one.

Compile-time safety​

How missing steps, changed parameters, and type mismatches become javac problems instead of CI surprises.

Feature-scoped steps​

Why SpecBinder avoids a global step-definition library by default, and how feature-scoped methods reduce accidental coupling between unrelated specifications.

Plain JUnit 5​

How generated tests remain ordinary JUnit 5 tests, so IDE runners, standard reports, CI integrations, tags, lifecycle methods, and debugging continue to work as expected.

Simple state management​

Why step state can just be Java state: fields, objects, page objects, API responses, calculated values, or captured exceptions.

No extra framework ceremony required.

Type-safe Data Tables​

How SpecBinder applies the same compile-time model to Gherkin Data Tables, turning table rows into generated, type-aware Java objects.

TDD-friendly Gherkin automation​

How generated test structure keeps the suite runnable and meaningful while a feature is still being built.

Green where you have finished.

Red where you have not.

Useful feedback all the way down.

What SpecBinder is not​

A short list, to keep expectations honest:

  • Not a Cucumber replacement for every project. If your current setup works well and your team is happy with runtime binding, that is a perfectly valid place to be.
  • Not a different specification language. SpecBinder reads standard Gherkin using Cucumber's parser.
  • Not a runtime framework. Tests run as plain JUnit 5. Maven, Gradle, Surefire, Failsafe, IntelliJ IDEA, and CI systems can treat them as Java tests.
  • Not magic. Compile-time generation means you see some errors earlier. That is the benefit. It is also the cost.

The short version​

SpecBinder focuses on one narrow part of the BDD toolchain:

turning formulated Gherkin specifications into maintainable, type-aware, JUnit-based automation.

If you like Gherkin, but would rather let the compiler find broken bindings before your test runner does, these articles explain the thinking behind the project.