Testing and change review
Backend testing: target the failure window, not just the happy path
By the BackendDrills editorial team · Published and checked October 6, 2026 · 7-minute read
Before you start: The behavior or invariant you want to verify. Find this reading in a study path →
A regression test should reject the behavior you intend to prevent. Choose the real boundary involved, arrange the adverse schedule deliberately, and assert its business consequences. The examples below are test designs, not runnable code tied to one framework version.
Write the assertion before the fixture
Suppose an import accepts a file and writes adjustments. A mock repository test verifies that save was called twice. That may establish orchestration, but it cannot show database uniqueness, commit behavior or rollback after the second write fails. The required assertion could instead be: no adjustment from the rejected import remains committed, while earlier valid imports remain intact.
| Concern | Useful boundary |
|---|---|
| Pure merge policy | Unit test with reordered, duplicate and invalid values. |
| Commit or constraint behavior | Real database and production-like transaction entry point. |
| Concurrent acceptance | Two connections with an explicit rendezvous. |
| Ambiguous remote completion | Controlled provider fixture and post-effect response loss. |
Watch the test's transaction
Spring test-managed transactions can roll back test work automatically. That is useful for isolation, but a transaction surrounding the test can mask a missing application transaction boundary. Verify externally invoked service behavior and inspect committed state from a fresh context. Check how transactions are associated with the test thread before using timeout features that execute work on another thread.
Inject the fault at the right point
A provider that fails before doing anything tests a clean rejection. It does not exercise the window where a provider performs an effect and its acknowledgment is lost. Draw a timeline with accept, persist, publish and acknowledge markers. Name the marker immediately preceding the injected failure. If the requirement concerns replay, the fixture must preserve the first attempt's durable state for the second attempt.
- Give the fixture a stable operation ID and predictable input.
- Release concurrent workers with barriers rather than long sleeps.
- Record actual completion, retry and rollback outcomes.
- Assert authoritative state after all relevant workers finish.
- Make cleanup and time limits explicit so a hung worker fails clearly.
Review the test as a change gate
Temporarily remove the intended protection in a local fixture and confirm that the test fails for the expected reason. A passing test that also passes without the fix offers weak protection. End with a short review note: the invariant, the adverse schedule, the assertion and any untested external assumption. Separate deterministic correctness tests from load experiments so performance noise does not obscure a broken contract.
Check the underlying behavior
Original illustrative examples, prepared with AI assistance and checked against the linked primary documentation. No customer incident or vendor endorsement is claimed. Our editorial approach.
Practice the next decision
Try a complete free backend drill: inspect evidence, make three decisions and review the reasoning. No account or card required.
Try a free incident drill →Selected practice from the study paths
- A mocked repository hides a uniqueness race · Full edition drill
- A fault test fails before the important window · Full edition drill
- Two orders buy the last item. · Full edition drill
- The double-click becomes a double charge. · Full edition drill
Free readings need no account. Full edition drills require verified access; opening a paid link does not expose its answers.