Writing Edge Cases That QA Can Actually Test

Writing Edge Cases That QA Can Actually Test
Daniel Marsh · Spec-first engineering notes

Here's how to stop edge cases from becoming production bugs: write them in the spec before implementation starts, in a format QA can turn into test cases without asking a single clarifying question. The edge cases that cause real incidents aren't exotic — they're the double-submit, the empty string in a field everyone assumed was populated, the permission check that passes because the order of operations was never specified. None of these are hard to anticipate. They're just easy to skip when the spec doesn't force you to name them.

Published on 2026-02-15 · ✓ Updated 2026-03-25 · 6 min read · Author: Daniel Marsh · Review policy: Editorial Policy

The edge cases nobody thinks to write down

Teams usually document the obvious ones: empty input, null value, 404. Those are fine. The cases that cause real incidents are the harder-to-anticipate ones — the situations that weren't exotic, just unconsidered.

CategoryWhat to CheckExample
Null / EmptyMissing fields, empty strings, zero-length arraysUser profile with email = ""
BoundaryLimits, thresholds, off-by-one99 vs 100 items in cart
DuplicateIdempotency, double-submit, re-importSame order submitted twice in 3 seconds
ConcurrencySimultaneous edits, race conditionsTwo users edit same record
PermissionRole boundaries, visibility rulesViewer tries to access admin endpoint
Retry / TimeoutNetwork failures, partial completionPayment timeout after charge submitted
State MachineInvalid transitions, out-of-order eventsCancelling an already-shipped order

The goal of writing edge cases in a spec isn't exhaustive coverage. It's to document every scenario where the system's behavior is non-obvious and where QA would need to ask a clarifying question before they could write a test. If QA can build the test independently, the edge case is done.

Null, empty, and malformed input

The most basic category. For any field in a form, API payload, or database record, the spec should state what happens when the field is null, empty string, or contains unexpected types. These should not be left to engineering judgment during implementation.

Edge cases — User profile update:
  - email = null          → reject with 422, message: "email is required"
  - email = ""            → reject with 422, message: "email is required"
  - email = "not-an-email"→ reject with 422, message: "email must be a valid address"
  - email = valid, 255 chars → accept
  - email = valid, 256 chars → reject with 422, message: "email exceeds max length"

QA should be able to copy these directly into a test plan. If they have to guess what "invalid email" should return, the spec has not done its job.

Boundary values

Boundary value analysis is one of the most reliable ways to find bugs, and it costs almost nothing to specify. For any numeric, date, or length-bounded field, write the cases at exactly the boundary, one below, and one above.

Engineers writing code will naturally test a round number — 50 items, 10 records. Nobody naturally tests 99 vs 100. That's why it has to be in the spec.

Concurrency and double-submit

Most product specs assume a single user doing one thing at a time. Production is not that. Write the concurrent cases explicitly so engineering knows what behavior is required and QA knows what to trigger.

Edge cases — Order submission:
  - User clicks "Place Order" twice within 500ms
    Expected: second request is rejected with 409 Conflict
    Response body: { "error": "duplicate_request", "orderId": "existing-id" }

  - Two browser tabs submit the same cart simultaneously
    Expected: one succeeds, one returns 409
    Idempotency key: client must send X-Idempotency-Key header
    If key absent: treat each request as independent (document this explicitly)

The spec does not need to specify how idempotency is implemented. It needs to specify what behavior QA should be able to verify.

Permission boundaries

Permission edge cases are frequently left out of specs because "access control is handled by the auth layer." That is not sufficient. The spec should state the behavior at specific permission boundaries, not assume a reader knows the permission model.

Retry and timeout paths

The system will time out. The upstream dependency will be slow. A payment gateway will return a 202 and never send the webhook. These paths need to be documented explicitly or engineering will each solve them differently.

Edge cases — Payment processing:
  - Stripe returns 200, but our webhook times out
    Expected: job retries webhook delivery up to 3 times with exponential backoff
    After 3 failures: order moves to "payment_pending_review" state, alert fires

  - User navigates away before confirmation screen loads
    Expected: payment intent is not cancelled; order is persisted if charge succeeded
    QA verification: simulate slow webhook, confirm order persists in DB

State machine violations

Any feature with a multi-step workflow has state transition rules. The spec should document which transitions are invalid and what happens when someone tries them — either via UI, API, or by replaying an old event.

Edge cases — Order state machine:
  Invalid transitions and expected behavior:
  - DELIVERED → CANCELLED: reject with 422, "order already delivered"
  - PENDING → SHIPPED (skipping CONFIRMED): reject with 422, "invalid state transition"
  - Replaying CONFIRM event on already-CONFIRMED order: idempotent, return 200 with current state

How to format edge cases so QA doesn't ask questions

The format matters as much as the content. Edge cases that are written as prose require QA to interpret them. Edge cases that follow a Given/When/Then or table format can be turned into test cases directly.

A simple rule: for every edge case in the spec, QA should be able to write the test name, the inputs, the trigger action, and the expected output without going back to the author. If any of those four things require a conversation, the edge case description is incomplete.

The minimum viable edge case checklist

For any feature that modifies data, involves user input, or calls an external service, run through this checklist before calling the spec ready:

Not every item applies to every feature. But reviewing each one forces a conscious decision. The ones you deliberately skip are at least documented omissions — not forgotten cases.

Keywords: edge cases · spec-first development · QA testability · acceptance criteria · boundary value testing

Editorial note

This article covers Writing Edge Cases That QA Can Actually Test for software delivery teams. Examples are illustrative engineering scenarios, not legal, tax, or investment advice.