agentleFS
rkhozinovrkhozinov/claude-skills/skills/atdd/SKILL.md

atdd

Skill0 starsChanged 4 months agoMITView on GitHub

Design and review acceptance / end-to-end tests with the four-layer model (spec / DSL / protocol driver / SUT). Use when writing or reviewing acceptance, e2e, or BDD tests, auditing whether a suite is well-layered, turning Gherkin or Given-When-Then scenarios into executable specs, building or critiquing a test DSL, page objects, or protocol driver, or when acceptance tests are flaky, order-dependent, or break on every refactor. Not for unit tests.

6 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use bdd, tdd and 1 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • TashanGKDSkill

    bdd

    行为驱动开发(BDD)流程助手。用 Given-When-Then 描述验收标准,包含 Feature 文件管理、步骤定义实现。用户提到 BDD、验收测试、Gherkin 时使用。

    Also in 3 projects that use this

  • GoogleSkill

    tdd

    Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.

    Also in 4 projects that use this

  • GoogleSkill

    code-review

    Adversarial systems, concurrency, memory-model, and architecture code review protocol. Use this skill whenever asked to review code, PRs, diffs, or branches in Filament.

    Also in 3 projects that use this

The file

We split this skill into the rules it gives an agent

7 rules. 0 are common, 6 are distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 6

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Never HOW. A test that names an endpoint, a status code, a CSS selector, or a table column is coupled to the implementation and will break …

    line 10
  2. Distinctive:

    🔴 Phase 1 — spec + DSL: Write the scenarios and the DSL that mirrors their wording.

    line 50
  3. Distinctive:

    🧼 Phase 3 — refactor + prove isolation: Run the suite in parallel, then run one scenario twice.

    line 62
  4. Distinctive:

    Do NOT clean up after each scenario.

    line 84
  5. Distinctive:

    Before Phase 1, these must exist — if they do not, build them first or ask:

    line 89
  6. Very specific:

    Never sleep. Poll with a timeout.

    line 99
  7. Distinctive:

    Read references/CHECKLIST.md and report violations by layer.

    line 108

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

ATDD — four-layer acceptance testing

Acceptance tests say WHAT the system does, in the language of the problem domain. Never HOW. A test that names an endpoint, a status code, a CSS selector, or a table column is coupled to the implementation and will break on the next refactor.

Unit-level red-green-refactor is a different skill (test-driven-development). This one is about the outer loop: one executable spec per business scenario, running against a production-like system.

The four layers

#LayerOwnsNever
1Executable specBusiness language. One scenario = one test. Each Given/When/Then line = exactly one DSL callCode, technical detail, explanatory comments
2DSLVocabulary of the domain, parameter defaults, aliasing for isolation, delegation to the driverAssertions, business logic, network calls, any SUT knowledge
3Protocol driverALL assertions. Talks to the SUT through its real public interface. Hides multi-step flowsHolding business state, framework-specific assert APIs
4SUTThe real deployed system: your DB, cache, queues, internal servicesBeing stubbed. It is the target, not test infrastructure

Layer 2 depends on the driver interface, never a concrete driver. That is what lets one spec run over HTTP, CLI, and UI — swap the driver at runtime (ACCEPTANCE_PROTOCOL=api|web|cli), touch no test.

Given the user has an account
And they have a completed todo "Buy milk"
When they archive it
Then it appears in the archive
dsl.user.hasAccount(email: "user@test.com")   # seeding:      has X
dsl.todo.hasCompleted(name: "Buy milk")       # seeding:      has X
dsl.todo.archives(name: "Buy milk")           # action:       verb
dsl.todo.confirmInArchive(name: "Buy milk")   # verification: confirm X

confirmInArchive, not assertInArchive — the DSL speaks business, and the assert lives one layer down. DSL method names and driver method names match 1:1.

Phase cycle

Three phases. Stop for human review after each one. Do not advance unaccepted.

🔴 Phase 1 — spec + DSL. Write the scenarios and the DSL that mirrors their wording. DSL calls driver methods that do not exist yet; compile/import failure IS the red state. First step of every scenario creates its own data partition. Fresh DSL instance per scenario. → review: does the DSL read like the scenario? Any assertion leaked in? Aliasing present?

🟢 Phase 2 — protocol driver. Implement the driver behind the interface. Assertions and failure logic all live here: method returns normally = pass, throws the language's native error = fail. Never a boolean, never expect() from the test framework. Error messages carry context: Expected tag 'kotlin' in list: [java, spring]. Poll with a timeout for async work, never sleep. Stub external third parties only. → review: interface implemented, tests execute (pass or fail depends on SUT readiness).

🧼 Phase 3 — refactor + prove isolation. Run the suite in parallel, then run one scenario twice. Both must be deterministic. Consolidate near-identical driver methods. Check against references/CHECKLIST.md. → review: final.

Isolation — the part everyone skips

Acceptance tests hit a real DB, so they are slow, so they must run in parallel, so they must not collide. Three levels:

  • System — stub ONLY third parties you do not control (payment gateway, email provider, the clock). Your own database, cache, and services are the SUT. Stubbing what you own means testing a system that does not exist.
  • Functional — every scenario creates its own partition (its own account / workspace / tenant) as its first action and works only inside it.
  • Temporal — every uniqueness-bearing identifier goes through an alias helper that appends a per-run counter: user@test.com → user@test.com1, user@test.com2. Same scenario, run twice, same result.

Alias identifiers (emails, usernames, order IDs, todo names). Use defaults for everything descriptive (passwords, roles, addresses) so the spec states only what the behaviour needs.

Do NOT clean up after each scenario. Aliased data accumulates harmlessly. Wipe once, at the start of the next run.

Required infrastructure

Before Phase 1, these must exist — if they do not, build them first or ask:

  • alias context (scenario-scoped counter) + parameter helper (alias / optional / optionalList)
  • driver interface + factory for runtime protocol selection
  • DSL root object composing per-domain children (dsl.user, dsl.todo)

Hard rules

  • Implement ONLY behaviour the spec states. No invented scenarios, no guessed edge cases. Worth-adding cases go in a suggestions list for the human — not into the suite.
  • Never sleep. Poll with a timeout.
  • The SUT is the single source of truth. Verify by asking the SUT, never by trusting state the test layer remembers.
  • Driver reaches the SUT only through the interface real consumers use. No direct function calls into the code, no reaching into its DB.
  • Adding a driver method means adding it to the interface, not just the implementation.

Reviewing an existing suite

Read references/CHECKLIST.md and report violations by layer.

Grep the DSL for assert / expect / should before anything else. A single hit is a violation, unconditionally — not a style preference, not "acceptable for a small suite." The assertion belongs in the driver, and a suite with asserts in the DSL is not well-layered however clean its imports look. Same for hardcoded identifiers: grep the specs for literal emails, usernames, and entity names — unaliased ones mean the suite cannot be re-run.

Then the rest, in usual order of frequency: status codes or selectors in the spec, stubbed internal DB, per-scenario cleanup, DSL reading raw SUT payload shapes.

Starting from a plain spec

Given a raw feature description with no scenarios, use references/PROMPT.md as the framing to produce the four layers.


Synthesized from Dave Farley's four-layer acceptance testing model (Continuous Delivery, cd.training) and the isolation, naming, and phase-gate rules of AAID by Dawid Dahl (MIT), whose aaid-bdd plugin is the fuller treatment of the same ideas.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.