A BDD testing framework for Scala 3 + ZIO 2 that connects Gherkin .feature files to type-safe ZIO step definitions.
# src/test/resources/features/account.feature
Feature: Account balance
Scenario: Deposit increases balance
Given an account with balance 100
When a deposit of 50 is made
Then the balance should be 150import zio.*
import zio.bdd.core.{Assertions, Suite}
import zio.bdd.core.step.ZIOSteps
import zio.schema.{DeriveSchema, Schema}
case class AccountState(balance: Int = 0)
object AccountState:
given Schema[AccountState] = DeriveSchema.gen[AccountState]
@Suite(featureDirs = Array("src/test/resources/features"), reporters = Array("pretty"))
object AccountSpec extends ZIOSteps[Any, AccountState]:
Given("an account with balance " / int) { (initial: Int) =>
ScenarioContext.update(_.copy(balance = initial))
}
When("a deposit of " / int / " is made") { (amount: Int) =>
ScenarioContext.update(s => s.copy(balance = s.balance + amount))
}
Then("the balance should be " / int) { (expected: Int) =>
ScenarioContext.get.flatMap(s => Assertions.assertEquals(s.balance, expected))
}- Type-safe step DSL —
"text " / string / " more " / intbuilds typed extractors; the step body receives(String, Int)parameters checked at compile time - ZIO environment injection — suites declare a
ZLayer-based environment; services are available in every step body viaZIO.service[T] - Scenario state — each scenario starts with a fresh
Sinstance; steps read/write it throughScenarioContext.get/ScenarioContext.update - Three-tier environment —
globalLayer(once per JVM),featureLayer(once per feature),scenarioLayer(meta)(once per scenario) for fine-grained resource sharing - Lifecycle hooks —
beforeAll,afterAll,beforeFeature,afterFeature,beforeScenario,afterScenario,beforeStep,afterStep - Full Gherkin support — Background, Scenario Outline (Examples tables), data tables, doc strings, tags
- Property-based testing —
@property(samples=N, seed=S)on a header-onlyExamples:block runs the scenario N times with ZIO TestGen-sampled values;HasGen[T]typeclass wires domain generators; named column overrides (| amount: smallAmounts |); automatic failure replay via.zio-bdd/failures/ - Flag matrix —
@flags(key=value)tags expand a scenario into N runs with different environment values - Tag filtering —
includeTags/excludeTagsin@Suiteor via--include-tags/--exclude-tagsCLI - Parallel execution — feature-level via
@Suite(parallelism = N), scenario-level via--scenario-parallelism N - Dry-run mode —
--dry-runvalidates step matching without executing step bodies - Built-in reporters —
pretty(ANSI colour tree) andjunitxml(JUnit 5 compatible XML) - Modular state —
TypeMapfor independent per-module state slices;HasLensfor nested state without.copychains - Step reuse —
HasService[A, R]typeclass lets step traits express service requirements without coupling to a concreteR - Typed table extraction —
table[T]reads Gherkin data tables intoList[T]using ZIO Schema - Scalar extractors —
string,word,int,long,double,boolean,bigDecimal,uuid,docString - HTTP mocking — a portable
MockControlSPI with Rift (container and no-Docker embedded FFM) and WireMock adapters; a type-safe mock DSL; capability negotiation;@mock(...)Gherkin fixtures — write one scenario, run it across backends (see Mocking)
// build.sbt
libraryDependencies += "io.github.etacassiopeia" %% "zio-bdd" % "1.5.2" % Test
Test / testFrameworks += new TestFramework("zio.bdd.ZIOBDDFramework")Requires Scala 3.3.4 and ZIO 2.1.17. zio-schema and zio-schema-derivation are pulled in
transitively and are needed to derive Schema[S] for your state type.
First-class editor support for .feature files — syntax highlighting, go-to-definition,
diagnostics, step completion, and gutter run actions (including running a single Scenario
Outline example) — is available for both VS Code and IntelliJ via
zio-bdd-tooling:
- VS Code — install zio-bdd from the
Visual Studio Marketplace,
or run
ext install etacassiopeia.zio-bddfrom the Quick Open palette. - IntelliJ IDEA — install zio-bdd from the JetBrains Marketplace (Settings → Plugins → Marketplace → search "zio-bdd"). No external plugins required.
Both bundle the language server, so there is no separate setup step.
| Document | Description |
|---|---|
| docs/quickstart.md | Zero to running test in 5 minutes |
| docs/concepts.md | Mental model: how the framework works |
| docs/step-dsl.md | Step DSL, extractors, and patterns |
| docs/property-testing.md | @property(...) tag, HasGen[T] registry, named generator overrides, failure replay, JUnit XML output |
| docs/mocking.md | HTTP mocking — portable MockControl SPI, DSL, adapters (Rift container + embedded, WireMock), @mock fixtures, capabilities |
| docs/index.md | Full documentation index — Gherkin syntax, state, layers, hooks, reporters, feature flags, cookbook, migrating from Cucumber, troubleshooting |
- zio-openfeature — ZIO bindings for the OpenFeature spec, using zio-bdd for conformance testing
- Rift — a Mountebank-compatible HTTP chaos proxy; drives its adapter conformance suite with zio-bdd (exercising a real backend end-to-end)
Apache 2.0 — see LICENSE.