jonnifyagile agents
jonnify / Agile Agent Workflow / A2 · Decomposition / A2.04 / A2.04.3 · Scenarios to tests

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

GIVEN a learner not enrolled in the course WHEN the learner enrols in the course THEN they appear in their enrolments exactly once enrolments: 1 holds
Happy path · enrol a learner not yet enrolled · count is 1 · holds — the learner appears in their enrolments exactly once.

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

✓ happy — enrol succeeds, count is 1 × sad — second enrol must not duplicate coverage 1 of 2 paths · NOT done — a second enrol can still duplicate
1 of 2 paths · happy passes, sad unguarded · NOT done — a second enrol can still duplicate. The rung passes its one test and ships the bug.

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

Related in this course