---
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:

1. Discover rules and concrete examples through conversation
2. Formulate `.feature` files in proper Gherkin illustrating those examples
3. 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](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.

```gherkin
# 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](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 changes` belongs in worktree steps, reusable across features
- **Conjunction steps** — don't combine things (`Given I have a repo and three worktrees`). Use `And`.
- **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:

1. **Create a minimal test entry point** — just `NewRunner` + `Run()` pointing at the feature file, with an empty suite struct
2. **Run `go test`** — gocuke prints suggested method signatures for every unmatched step
3. **Paste the suggestions** into your step definition files and flesh out assertions/setup, but leave implementation calls hitting code that doesn't exist yet
4. **Run `go test` again** — tests fail (red) because the behaviour isn't implemented
5. **Implement the minimum code** to make one scenario pass (green)
6. **Refactor** if needed, keeping tests green
7. **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:

1. Read the informal spec to understand the rules and examples
2. Identify which `Rule` groups emerge from the requirement headings
3. Write each scenario in proper Gherkin syntax, making it more declarative if the original was implementation-coupled
4. Remove incidental details that don't affect the outcome
5. Add `Background` where multiple scenarios share the same preconditions
6. Look for opportunities to use `Scenario Outline` for 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](references/bdd-practices.md)
- **Gherkin syntax**: See [references/gherkin-reference.md](references/gherkin-reference.md)
- **gocuke API and property-based testing with rapid**: See [references/gocuke-api.md](references/gocuke-api.md)
