A2.04 · Acceptance · dive 3
Scenarios become tests
A behaviour has a happy path and sad paths. Each scenario becomes an acceptance test — implemented against, accepted against.
The Author implements against each scenario; the Operator accepts against it. A rung is not done when the happy path passes — it is done when the happy path passes and the sad paths hold. The scenario set is the definition of done, and the seed of the A4 spec layer and its harness. Run the enrol set on the right.
Run the enrol acceptance set · choose a path
Happy and sad paths
A behaviour is more than the case where everything goes right. The happy path is the enrol that succeeds; the sad paths are the defined, expected deviations the behaviour must still handle — a second enrol that must not duplicate, an enrol in a course that does not exist. A sad path is not an error to ignore; it is part of the agreed behaviour, so it is part of the definition of done.
Each scenario maps to exactly one acceptance test, and the test is read from both sides. The Author implements against it: the scenario is the precise behaviour to satisfy. The Operator accepts against it: the scenario is the check that says the rung is done. The same scenarios that were the shared spec (A2.04.2) are now executable acceptance tests — nothing is re-authored, only run.
- happy path
- The behaviour when everything is in order — the enrol that succeeds.
- sad path
- A defined, expected deviation the behaviour must still handle — a second enrol that must not duplicate.
- acceptance test
- One scenario, run from both sides: the Author implements against it, the Operator accepts against it.
A green happy path is not done: a rung is done only when its sad paths hold too — otherwise it passes its test and still ships the bug the sad path describes.
Done is a closure over the paths
The definition of done for a rung is not one passing test; it is the whole scenario set passing. Include only the happy path and a second enrol can still duplicate — the rung passes its one test and ships a defect. Include the sad path too and the set is closed: every agreed behaviour, the success and the deviation, is checked. Done is a closure over the paths, not a single green light.
Toggle the paths into the acceptance set. The happy path alone leaves the sad path unguarded — shown in burgundy as not done. Adding the sad path closes the set to done. The readout reports how many of the rung’s paths are covered and whether the definition of done is complete, computed from the model.
Cover the rung · toggle each path into the set
Done is a closure over the paths: the happy path passing is one green light, not a definition of done — the rung is done only when the sad paths hold too.
Scenarios to tests on the Portal
The enrol rung’s acceptance set is one happy scenario and one sad scenario. The Author
implements the enrol path and runs both as tests; the Operator accepts the rung against both. The
only engine surface asserted is Portal.ID.generate/1, which mints the
enrolment id — the rest of the OTP machinery is the companion /elixir
course’s territory, not asserted here.
# Happy path Scenario: a learner enrols Given a learner not enrolled in "Functional Programming" When the learner enrols in "Functional Programming" Then the learner appears in their enrolments exactly once # Sad path (idempotent) Scenario: enrolling twice Given a learner already enrolled in "Functional Programming" When the learner enrols in "Functional Programming" again Then no duplicate is created — the learner appears exactly once # As acceptance tests the Author implements against and the Operator accepts against: id = Portal.ID.generate(:enrolment) # one enrolment id assert count_enrolments(learner, course) == 1 # happy path holds # enrol again … assert count_enrolments(learner, course) == 1 # sad path holds — idempotent
The principle
A rung is done when its happy path and its sad paths both pass as acceptance tests — the scenario set is the definition of done.
On the Portal
The enrol rung is done when both scenarios hold — the learner enrols once, and a second enrol does not duplicate — each run as an acceptance test the Author implements against and the Operator accepts against.
Happy and sad paths, each an acceptance test, together the definition of done — implemented against by the Author, accepted against by the Operator.
Recap — the set is the definition of done
A behaviour has a happy path and sad paths; each scenario is an acceptance test the Author implements against and the Operator accepts against. The set of them is the definition of done — a closure over the paths, not a single green light — and the same scenarios that were the shared spec are now the checks. The A4 spec layer turns this scenario set into a runnable specification with a harness that executes it on every change (taught there, named here). With acceptance pinned, the chapter’s later modules split stories too large to estimate and order the value ladder.
A2.04 closes acceptance. Returning to the A2.04 module hub recaps the three dives; the chapter’s later modules build on a story that already carries a checkable definition of done.
References
Primary sources for scenarios as acceptance tests and the definition of done, and where they connect in the course.
Sources
- Adzic, G. — Specification by Example — executable examples as the living acceptance tests.
- Cucumber — Gherkin reference — scenarios, including the deviation cases, in one feature.
- Cohn, M. — User Stories Applied — conditions of satisfaction as the test of done.
Related in this course
- A2.04 · Acceptance criteria with Given/When/Then — the module hub.
- A2.04.2 · Examples as the spec — the previous dive.
- A2.03 · INVEST — the Testable story this makes runnable.
- A1.04 · Two layers: roadmap and specs — the spec layer the A4 harness builds on.
- A2 · Decomposition — the chapter.