bcquality/microsoft/knowledge/testing/test-one-when-per-test.md
Michael Dieringer a4d85c3e9e Add 18 more community AL/BC patterns across appsource, data-modeling, error-handling, security, style, testing, ui, upgrade, and web-services
Second contribution from CURABIS ApS, generalized from patterns observed across real AppSource/PTE development. Cross-checked against the current microsoft/knowledge corpus before opening; several originally-drafted candidates were dropped as duplicates of existing files.
2026-09-21 22:42:49 +02:00

2.7 KiB

bc-version domain keywords technologies countries application-area
all
testing
when
single-action
bdd
atdd
given-when-then
flow-test
regression-test
al
w1
all

Keep exactly one WHEN per test, with narrow exceptions for flow and defect-then-fix tests

Description

Each test procedure should contain exactly one [WHEN] block: one action that triggers the behaviour under test. A test with multiple WHENs — "do A, then do B, then check C" — is two or more tests in disguise. Splitting them gives failure isolation (a failing test points at one action, not an ambiguous sequence) and keeps each test readable as a single, falsifiable claim. A precondition action, such as posting a document so a ledger entry exists to assert against, belongs in [GIVEN]; only the action actually being asserted belongs in [WHEN].

Best Practice

Give each test one [WHEN] and one focused claim. A procedure name containing "And" or "Then" in the middle (GetPrice_AndDiscount_ReturnsValues) is a strong signal the test should be split.

See sample: test-one-when-per-test.good.al.

Anti Pattern

A test that performs a first action, then a second unrelated action, then asserts on both — mixing two falsifiable claims into one procedure so a failure can't tell you which action broke.

See sample: test-one-when-per-test.bad.al.

Flow tests — a deliberate exception

A flow test verifies the accumulated outcome of a genuinely multi-round business process (partial receipt then invoicing, several posting rounds against one document), where the sequence itself is the scenario — splitting it would lose the interaction under test. Multiple [WHEN] blocks are allowed only when the procedure name declares the flow, each [WHEN] is labelled as one round of a single scenario rather than an unrelated action, and the [THEN] asserts the accumulated end-state rather than assertions that decompose cleanly per action (if they do decompose cleanly, it is still two tests in disguise). Outside this shape, unit-level tests keep the strict one-WHEN rule.

Defect-then-fix tests — a second, narrower exception

A test that reproduces a specific broken state and then verifies a subsequent action corrects it is not the same shape as an unrelated-action test, even though its [THEN] assertions decompose cleanly per step — clean decomposition is expected here, not a sign of two unrelated tests. This shape is permitted only when the second [WHEN] cannot be meaningfully tested without the first (the fix only affects the exact stale state the first action produced, so splitting would just re-run the first action inside a second test's [GIVEN]), and the procedure name communicates the before/after relationship.