Module 3 · Python for SDETs

API Testing
with requests

Drive every HTTP verb against a real API — and read what comes back

GET / POST PUT / DELETE status & JSON CRUD lifecycle
AI with Rufat
Anatomy of a response
r = requests.get("…/api/products/1")
r.status_code # 200
r.ok # True for any 2xx/3xx
r.headers # case-insensitive dict
r.json() # body → dict / list
🔢

.status_code

the integer status (200, 201, 404…)

.ok

True for any status below 400

📋

.headers

response headers, case-insensitive

📦

.json()

parse the body into Python

AI with Rufat
Each verb, its success status

The four HTTP verbs

GET
200
read a resource
POST
201
made it; body has the new record
PUT
200
updated
DELETE
200
removed
📌requests never raises on a 4xx — the status is just data you assert. Reads use plain requests; writes reseed with the reset_db fixture so re-runs stay clean.
AI with Rufat
json= sends a body, the server does work
payload = {
"email": "customer@test.io",
"items": [{"product_id": 1, "quantity": 2}],
}
r = api.post("…/api/orders", json=payload)
201Created
total: 59.98 # 29.99 × 2, server-side
json= also sets Content-Type for you. The total is computed — assert it with pytest.approx.
AI with Rufat
The shape of a real API test

A full lifecycle, one test

CREATE
POST → 201
READ
GET → 200
UPDATE
PUT → 200
DELETE
DELETE → 200
CONFIRM GONE
GET → 404
🔁Every verb in one coherent test — and it cleans up after itself. Prove the effect (the follow-up GET → 404), not just the delete status.
AI with Rufat
🌐

The whole
API surface

Read and write, assert status + body, and run a full CRUD lifecycle

🧪
Practice
CRUD against TestMarket Lab — capture the new id from the POST response
♻️
reset_db
Writes reseed first, so your tests stay independent and re-runnable
➡️
Module 4
Negative & validation — 400 / 401 / 404 / 409, failing the right way
AI with Rufat
← / → · space