# Test Case Specification

Turns agreed criteria into cases someone can run — each with its data, its expected result, and the criterion it exists to cover.

## Deliverable

One Markdown document, `test-cases.md`, in the structure set out under **Output** below. It takes the output of **Acceptance Criteria Authoring** and becomes the material the **Regression Suite Audit** later judges.

## Required inputs

- **The criteria or specification to cover** — sections 3 to 6 of `acceptance-criteria.md` are the expected form; any written statement of agreed behaviour will do.
- **The level the cases are written for** — taken from the test strategy where one exists. A case with no level cannot be placed, automated or owned.

Without both, stop. Never write cases from the implementation: a case derived from the code asserts what the code does, and it keeps passing whether that is right or wrong.

## Optional inputs

- The test data available: what exists, how it is created, what is restricted
- The environment the cases will run in, and how it differs from production
- Existing cases covering the same area
- Known defects in the area and the conditions that triggered them
- The interfaces under test: screens, endpoints, scheduled jobs, messages
- Who will run the cases, and whether by hand or through the test runner

An absent optional input does not stop the specification. Each case records the data it needs; where the source of that data is not known, the case is marked `data source unknown` and listed under **Missing information** rather than written against data somebody assumes exists.

## Execution

**1 — Take the criteria one at a time.** Every criterion gets at least one case. A criterion that cannot be turned into a case is reported back as untestable as written, with what makes it untestable — it is never approximated by a case that tests something near it.

**2 — Divide the inputs into classes.** Group the values the behaviour treats alike, write one case per class, then add a case at each edge of a class and at the first value outside it. The aim is a small set whose coverage can be argued, not a large set whose coverage is hoped for.

**3 — State the preconditions.** Per case: the account and its permissions, the state of the data, and the state of every system the case depends on. A precondition nobody can create is a blocker, and it is recorded as one rather than left for whoever runs the case to discover.

**4 — Name the data.** Per case: what data it needs, where it comes from — a fixture, generated, seeded, or requested from whoever owns it — and whether another case may reuse it. Data that does not yet exist is named as required, never invented inside the case.

**5 — Write the steps and the expected result.** One action per step, in the order performed. The expected result is stated precisely enough to fail on: the state, record, message or response that must be observed. A result saying the behaviour works as expected cannot fail, and so cannot pass.

**6 — Write the cleanup.** What the case creates, what it must remove or reset, and what it may leave behind. A case that leaves state behind turns its own mess into the next case's failure, and the next case is the one that gets investigated.

**7 — Trace both ways.** Each case names the criterion it covers; each criterion names the cases covering it. Criteria with no case are coverage gaps. Cases with no criterion are either a missing criterion or a case nobody needs — both are reported, neither is deleted here.

## Output

`test-cases.md`, in this order:

- **1. Input and date** — which criteria are covered, the level the cases are written for, who wrote them and when
- **2. Cases** — per case: identifier, title, level, preconditions, data, steps, expected result, cleanup, and the criterion covered
- **3. Coverage analysis** — per criterion: the classes and boundaries identified, and the cases covering each
- **4. Criteria with no case** — the criterion, what prevents a case, and what is needed to write one
- **5. Cases with no criterion** — the case, what it asserts, and the decision the accepter must make about it
- **6. Data requirements** — per data set: what it is, where it comes from, whether it is restricted, and who owns it
- **7. Blocked cases** — cases that cannot run, the precondition or access they need, and who can supply it
- **8. Missing information** — what stopped a case being specified, and who can unblock it

## Validation

The suite is ready when all of these hold:

- Every criterion in the input appears in section 2 or section 4
- Every case names its preconditions, its data source and its cleanup, or states that it needs none
- Every expected result names something observable, and would fail if the behaviour changed
- Every case names the criterion it covers, or appears in section 5
- No value, limit or format appears in a case that the input did not supply
- Sections 4 and 5 are present even when empty, and say so when they are

Fail the run if an expected result cannot be observed, or if a case depends on data that no input supplied.

## Failure handling

- **No criteria supplied** — stop. Report that cases cannot be specified from an implementation, and name what is needed first.
- **A criterion is untestable as written** — do not approximate it. Record it in section 4 with what makes it untestable, and return it to whoever wrote it.
- **No environment or no test data** — specify the cases in full, mark them `NOT RUN`, and list the access needed in section 7. A specified case that has not run is honest; a case recorded as passing without running is worse than no case.
- **Contradictory criteria** — write no case for the contradiction. Record both readings in section 8 as blocking, name both sources, and leave the choice to the accepter.
- **Partial material** — specify what the material supports, mark the rest `INCOMPLETE — pending <question>`, and report the coverage the suite actually has rather than the coverage it looks like it has.
