An OpenAPI spec is a test generator's dream input: typed, bounded, and explicit about errors. AI turns it into a full suite — happy paths, auth, negatives, contracts — in minutes. Then comes the professional step: attack your own suite with schema fuzzing and planted weak spots, because generated asserts are reliably softer than they look.
Tier: Core · Workflow area: Automation engineering
This playbook builds an API suite from a spec in two movements — generation with explicit assertion depth, then adversarial self-audit with Schemathesis and targeted assert-weakening checks. The suite that survives its own attack is the one allowed to guard the API.
When NOT to use:
pip install schemathesis) plus your HTTP test stack (pytest + httpx, or Postman/Bruno).Validate the spec itself:
npx @redocly/cli lint openapi.yaml
Broken or vague specs (bare type: object, missing 4xx responses) cap everything downstream — tighten the worst offenders before generating.
Generate the suite with assertion depth spelled out. The prompt's rules are the difference between real checks and status == 200 theater:
From this OpenAPI spec, generate pytest tests using httpx for the
/orders endpoints.
For EVERY request assert ALL of:
- exact status code (200 vs 201 matters),
- response validates against the spec's response schema (use
jsonschema, load schemas from the spec, don't restate them),
- business invariants stated in descriptions (e.g., "total equals sum
of line items"),
- error bodies match the documented error schema — not just the code.
Include per endpoint: happy path, missing/invalid auth (401/403
distinct), malformed body (422 with field-level errors), not-found,
and boundary values from schema constraints (maxLength, minimum...).
Base URL and token from env vars. No hardcoded IDs — create test data
via the API itself and clean up.
A generated test worth keeping looks like:
def test_create_order_rejects_negative_quantity(client):
r = client.post("/orders", json=order_payload(quantity=-1))
assert r.status_code == 422
body = r.json()
assert body["errors"][0]["field"] == "items[0].quantity"
validate(body, ERROR_SCHEMA) # documented error contract, enforced
Run the suite, then fuzz the same surface with Schemathesis:
pytest tests/api/ -q
schemathesis run openapi.yaml --base-url https://staging.example.com \
--checks all --hypothesis-max-examples 200
Schemathesis derives property-based cases from the schema — everything Schemathesis finds that your generated suite didn't is a measured gap in the generation. Triage its failures: real API bugs get filed; spec-vs-implementation mismatches get a spec fix; and each gap class gets a permanent test added to the suite.
Attack your own assertions. The API-tier equivalent of mutation testing — plant response bugs and count detections. Run the suite against a wrapper that deliberately corrupts responses:
Write a small FastAPI reverse-proxy for my staging API that applies one
corruption per run, selected by env var MUTATION:
drop_field (remove a required response field), wrong_type (stringify a
number), status_swap (200→201), extra_2xx (return 200 for a request
that should 404), empty_error_body.
I will run my suite against it and log which mutations go undetected.
MUTATION=drop_field uvicorn proxy:app --port 9000 &
API_BASE=http://localhost:9000 pytest tests/api/ -q
Every mutation that passes the suite is a weak assert. Feed the survivors back to the assistant to strengthen, exactly like pb-09's mutant loop.
Wire into CI as a contract gate — suite plus a Schemathesis smoke (--hypothesis-max-examples 20) on every PR that touches the API or the spec, full fuzz nightly.
Keep the spec as the single source of truth in the tests — load schemas from the file rather than letting the assistant restate them inline, or the suite will silently stop noticing spec drift, which was half the reason you built it.
pm.test / Bruno asserts) instead of pytest; keep step 4 by running the collection through Newman against the corruption proxy.Generating an API suite is the cheap half; the suite earns trust only after surviving Schemathesis and a planted-corruption audit. Test the tests first — then let them gate the contract.