`npm run format:check` (a CI gate) had drifted red across 44 files — pre-existing files plus recently-added ones committed without formatting. Ran `prettier --write .`; no logic changes. Also regenerates documentation.json (compodoc reflects the reformatted component sources). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
76 lines
3.8 KiB
Plaintext
76 lines
3.8 KiB
Plaintext
import { Meta } from '@storybook/addon-docs/blocks';
|
|
|
|
<Meta title="Foundations/BDD" />
|
|
|
|
# Behaviour-driven tests
|
|
|
|
Tests here read as **specifications of behaviour**, not checks of implementation. A test
|
|
says what the system _does_ — in the domain's own words — so a failing test names a broken
|
|
behaviour, and the suite doubles as living documentation. This is the BDD half of the
|
|
[Testing strategy](?path=/docs/foundations-testing-strategy--docs) (which owns _what to
|
|
test, by layer_); BDD owns _how each test is phrased and scoped_.
|
|
|
|
## Three rules
|
|
|
|
### 1. `describe` = the subject, `it` = one observable behaviour
|
|
|
|
The `describe()` block names the unit under test; each `it()` states a single behaviour in
|
|
**declarative present tense** — the implicit subject is "it". No `should`, no
|
|
Given/When/Then ceremony: present-tense declaration already reads as a spec.
|
|
|
|
```ts
|
|
describe('parsePostcode', () => {
|
|
it('normalises to "1234 AB" (uppercase, single space, trimmed)', () => { … });
|
|
it('rejects malformed input', () => { … });
|
|
});
|
|
```
|
|
|
|
Read top-to-bottom it _is_ the spec: "parsePostcode — normalises to 1234 AB; rejects
|
|
malformed input."
|
|
|
|
### 2. One behaviour per test
|
|
|
|
A test asserts **one behaviour**, not one `expect()`. Several assertions that pin down the
|
|
_same_ behaviour belong together; assertions about _different_ behaviours belong apart.
|
|
|
|
| Keep together (one behaviour) | Split apart (separate behaviours) |
|
|
| -------------------------------------------------------------- | -------------------------------------------------------- |
|
|
| A `Result`'s `.ok` then its `.value` | The `ok` branch **and** the `err` branch of a transition |
|
|
| A whole-object `toEqual` | An invalid-input case **and** a valid-input case |
|
|
| A loop asserting one rule over many inputs | Two independent state transitions |
|
|
| A truth-table (`draft` → true, `approver` → false) of one rule | An authorization check **and** a rendering check |
|
|
|
|
A title that needs `/`, `;`, "then" or "and" to join two behaviours is the smell — split it,
|
|
and each half gets its own present-tense name.
|
|
|
|
### 3. Speak the ubiquitous language (the DDD tie-in)
|
|
|
|
Test names use the **domain vocabulary**, not technical jargon — the same words as the
|
|
[bounded contexts](?path=/docs/foundations-domain-driven-design--docs): a _behandelaar_
|
|
drafts, a _beoordelaar_ approves, a _herregistratie_ is _ingediend_. The test name is
|
|
readable by someone who knows the domain but not the code.
|
|
|
|
```ts
|
|
it('drafter cannot approve or reject even when submitted', …);
|
|
it('confirmed dutch proficiency requires taalvaardigheid proof', …);
|
|
```
|
|
|
|
## How it fits TDD & DDD
|
|
|
|
- **TDD** — the loop is red → green → refactor: write the behaviour as a failing `it`, make
|
|
it pass, then clean up. Because tests describe behaviour (not internals), a refactor that
|
|
preserves behaviour keeps them green. Pure domain logic is tested directly — no `TestBed`
|
|
(see [Testing strategy](?path=/docs/foundations-testing-strategy--docs)).
|
|
- **DDD** — behaviour is expressed in the ubiquitous language, so the spec and the code
|
|
share one vocabulary. Domain rules (reducers, value-object parsers, policies) are the
|
|
richest specs; the wire boundary is tested as "rejects malformed input", the UI as
|
|
Storybook stories.
|
|
|
|
## Where to look
|
|
|
|
Canonical behaviour specs in the repo: `registratie/domain/value-objects/postcode.spec.ts`
|
|
(parser behaviour), `registratie/domain/registratie-wizard.machine.spec.ts` (one transition
|
|
per test), and backend `AuthzTests.cs` (rule truth-tables). The
|
|
[Testing strategy](?path=/docs/foundations-testing-strategy--docs) page maps which layer
|
|
gets which kind of test.
|