Lesson 24 / 27
Testing the API and the Contract
Combine unit, integration, contract and breaking-change tests.
Layers of confidence
Test an API at several levels. Unit tests cover business logic. Integration tests call the real HTTP endpoints against a test database and check status codes, headers and bodies, including error cases and the auth/ownership rules. Contract tests verify that responses match the OpenAPI schema (and, with consumer-driven contracts such as Pact, that the API still satisfies what real consumers expect). A breaking-change check in CI diffs the new spec against the released one (tools like oasdiff do this) and fails the pull request on incompatible changes unless a new version is intended. Add tests for pagination edges (empty, last page), idempotent retries, rate-limit responses and webhook signature verification. Run a smoke test against production after each deploy.
API tests in pytest (illustrative)
These check the behaviours demonstrated earlier in the course against a test client. client is your framework's test client fixture.
def test_idempotent_payment(client):
h = {"Idempotency-Key": "k-1"}
first = client.post("/v1/payments", json={"amount": 500}, headers=h)
again = client.post("/v1/payments", json={"amount": 500}, headers=h)
assert first.status_code == 201 and again.status_code == 200
assert first.json() == again.json()
assert again.headers["Idempotent-Replayed"] == "true"
def test_other_users_order_is_404(client, token_a, order_of_b):
r = client.get(f"/v2/orders/{order_of_b}", headers={"Authorization": f"Bearer {token_a}"})
assert r.status_code == 404
def test_last_page_has_null_cursor(client):
assert client.get("/v1/items?limit=100").json()["next_cursor"] is NonePin versions in tests
Keep a test suite per supported version. When you retire a version, delete its tests with the code, not before.
Quick check: What does a CI breaking-change check do?
- Deletes old versions
- Deploys to production
- Compares the new spec with the released one and flags incompatible changes
- Encrypts the spec
Answer
Compares the new spec with the released one and flags incompatible changes — Automatic diffing stops accidental breaking changes from reaching users.