A BDD testing framework integrating Gherkin-style tests with ZIO’s effect system
zio-bdd is a Scala 3 + ZIO 2 BDD testing framework. Write plain Gherkin .feature files;
implement type-safe step definitions; run them through sbt with full ZIO dependency injection.
New to zio-bdd? Read in this order:
.feature file becomes
ZIO effects, what R and S mean, how state is isolated per scenario.string, int, table[T],
docString, regex, oneOf, etc.) plus the StepEffect / StepIO type aliases.Examples: rows, learn the @property(...) tag to sample generated values instead.| Document | What it covers |
|---|---|
| State Management | ScenarioContext, Stage, FeatureContext, TypeMap, HasLens, ScenarioLens, withSnapshot, GivenS/WhenS/ThenS |
| Environment & Layers | R type parameter, three-tier model (globalLayer, featureLayer, scenarioLayer), flagLayer, HasService |
| Hooks | beforeAll, afterAll, beforeFeature, afterFeature, beforeScenario, afterScenario, beforeScenarioTagged, beforeStep, afterStep |
| Step DSL | All extractors, StepEffect, StepIO, InlineStepMethods, pending, withSnapshot, soft assertions |
| Gherkin Syntax | Complete Gherkin reference — Feature, Background, Scenario, Scenario Outline, Examples, Rule, tags, data tables, doc strings |
| Property-Based Testing | @property(...) tag, HasGen[T] registry, named generator overrides, failure replay, JUnit XML output |
| Running Tests | @Suite annotation, sbt commands, CLI flags, dry-run, tag filtering, parallelism, step timeout, IDE integration |
| Feature Flag Testing | @flags(k=v) matrix expansion, flagLayer, ScenarioMetadata.flagValues, OpenFeature / Optimizely patterns |
| Reporters | pretty (console tree), junitxml (CI reports), StreamingReporter, LiveProgressReporter, custom reporters |
| Performance | Parallelism tuning heuristics, log-capture memory characteristics, state-mechanism cost, startup & discovery |
Portable HTTP mocking — write a scenario once and run it across Rift (container and no-Docker embedded FFM) and WireMock, negotiating capabilities per backend.
| Document | What it covers |
|---|---|
| Mocking Overview | The portable MockControl SPI, MockSpace + isolation (PerInstance/Correlated), the request/response model, MockSource variants |
| Mock DSL | The zio.bdd.mock.dsl.* builder — matching requests, building responses, rule precedence, the stateful-scenario builder, raw JSON sources |
| Mock Adapters | Rift (managed/connect), WireMock, and the embedded FFM provider (single zio-bdd-rift artifact, JDK 22+ runtime); the capability × adapter matrix; choosing one |
| Mock Gherkin Integration | MockSteps mixin, the @mock(name) tag + MockFixtures, the catalog pattern, Stage |
| Mock Advanced | Capability accessors (faults, scenarios, state inspection, scripting, proxy/record, templating), the provisionNative escape hatch, capability negotiation |
| Document | Use when |
|---|---|
| Cookbook | You have a specific task: structuring a multi-module suite, passing data between steps, writing HTTP tests, date-relative parameters, soft assertions, selective tagging |
| Mock Cookbook | You want mocking recipes: stand up a backend as a layer, a portable MockSteps scenario, @mock(...) fixtures, injecting faults across adapters |
| Troubleshooting | Something is wrong: compiler errors, startup failures, state not updating, missing step definitions, timeouts |
| Migrating from Cucumber | You are converting a Cucumber-JVM + cucumber-scala suite to zio-bdd |
“Which state mechanism do I use?” → See State Management §6 for the decision table.
“Stage or ScenarioContext?”
→ Stage for ephemeral pipeline data
(event payloads, intermediate results). ScenarioContext
for values that Then steps need to assert on.
“GivenS or Given?”
→ Use GivenS/WhenS/ThenS when the step reads state at the top. Use Given/When/Then
when the step does not read state at all. See cookbook.md §14.
“globalLayer, featureLayer, or scenarioLayer?”
→ globalLayer — shared across the entire run (connection pools, embedded servers).
featureLayer — fresh per feature file.
scenarioLayer(meta) — fresh per scenario; use when tag-based conditional layers are needed.
See layers.md §2.
“My step trait can’t call Given — compile error?”
→ Add the self-type: trait MySteps { self: ZIOSteps[R, S] => ... }.
See troubleshooting.md.