name: testing-with-gocuke-and-gherkin description: "Drives BDD, red/green TDD, and property-based testing in Go projects using gocuke and Gherkin feature files. Use when writing Gherkin scenarios, formulating feature files, creating gocuke step definitions, or following BDD workflows in Go. NOT for non-Go projects, other BDD frameworks, or other contexts." license: GPL-3.0-or-later metadata: author: Amolith amolith@secluded.site
BDD testing in Go with gocuke and Gherkin. Follows Cucumber's three practices: Discovery → Formulation → Automation, driven by red/green TDD.
Workflow
The BDD cycle for each behaviour:
- Discover rules and concrete examples through conversation
- Formulate
.featurefiles in proper Gherkin illustrating those examples - Automate by wiring up gocuke step definitions, watching them fail (red), and implementing until they pass (green)
Do not skip steps. Discovery before formulation. Formulation before automation. Automation before implementation. See references/bdd-practices.md for detail on each practice.
Again. Resist the urge to implement first. User prompts might push towards writing code before the behaviour is fully thought through. That defeats the purpose. The value of this process is that writing scenarios first forces you to think clearly about what the system should do, surface edge cases, and catch misunderstandings before a line of implementation exists. If scenarios are written after the code, they just describe what was built, not what should have been built. Write the .feature file, watch it fail, then implement.
Formulating feature files
Write declarative Gherkin that describes behaviour, not implementation. Imagine it's 1922 — no computers exist. Good scenarios read like specifications, not test scripts.
# Good — declarative, behaviour-focused
Scenario: Clean worktree reports no changes
Given a worktree with no uncommitted changes
When the status is checked
Then the worktree is reported as clean
# Bad — imperative, implementation-coupled
Scenario: Clean worktree
Given I run "git status --porcelain" and it returns empty
When I call the Status function with the path "/tmp/wt"
Then the Clean field is set to true
Ask: "will this wording need to change if the implementation does?" If yes, rewrite it.
For full Gherkin syntax (keywords, Rule, Background, Scenario Outline, data tables, doc strings, tags), see references/gherkin-reference.md.
Anti-patterns to avoid
- Feature-coupled steps — step definitions should be grouped by domain concept, not by feature file. A step like
Given a worktree with uncommitted changesbelongs in worktree steps, reusable across features - Conjunction steps — don't combine things (
Given I have a repo and three worktrees). UseAnd. - Incidental details — don't include specifics that don't affect the outcome. If the worktree name doesn't matter, don't name it.
- UI/implementation coupling — scenarios should survive refactors. "When the status is checked" not "When I call Status()".
File layout
features/ # Gherkin feature files
├── vcs/
│ ├── detection.feature
│ ├── worktree_discovery.feature
│ └── worktree_lifecycle.feature
├── sidebar/
│ └── status_display.feature
└── startup/
└── boot_sequence.feature
internal/
├── vcs/
│ ├── vcs.go
│ ├── vcs_test.go # gocuke test entry points
│ ├── steps_detection.go # step definitions by domain concept
│ ├── steps_worktree.go
│ └── steps_status.go
Feature files live under features/, grouped by domain area. Step definitions live alongside the code they test, grouped by domain concept — not mirroring the feature file structure.
Red/green TDD cycle
Once a .feature file is formulated:
- Create a minimal test entry point — just
NewRunner+Run()pointing at the feature file, with an empty suite struct - Run
go test— gocuke prints suggested method signatures for every unmatched step - Paste the suggestions into your step definition files and flesh out assertions/setup, but leave implementation calls hitting code that doesn't exist yet
- Run
go testagain — tests fail (red) because the behaviour isn't implemented - Implement the minimum code to make one scenario pass (green)
- Refactor if needed, keeping tests green
- Repeat for the next scenario
Let gocuke guide the wiring. Don't hand-write step definitions from scratch when the runner will tell you exactly what it needs.
Work one scenario at a time. Don't implement ahead of failing tests.
Converting informal specs to feature files
When the project has informal markdown specs with Gherkin-ish structure (bullet-point Given/When/Then), convert them methodically:
- Read the informal spec to understand the rules and examples
- Identify which
Rulegroups emerge from the requirement headings - Write each scenario in proper Gherkin syntax, making it more declarative if the original was implementation-coupled
- Remove incidental details that don't affect the outcome
- Add
Backgroundwhere multiple scenarios share the same preconditions - Look for opportunities to use
Scenario Outlinefor parameterised variants
The goal is feature files that a non-developer could read and confirm: "yes, that's the behaviour we want."
Editor tooling
The Cucumber language server cannot discover gocuke step definitions. It expects explicit registration calls (Godog-style ctx.Given("pattern", fn)), not gocuke's runtime reflection. "Undefined step" warnings are false positives; disable the Cucumber language server for gocuke projects.
Further reference
- BDD practices (Discovery, Formulation, Automation): See references/bdd-practices.md
- Gherkin syntax: See references/gherkin-reference.md
- gocuke API and property-based testing with rapid: See references/gocuke-api.md