Test Below the UI: Your First API Tests in Python
Testing only through the UI is slow and misses what anyone can do with curl. Write your first pytest tests against the API: the €50.00 boundary, the order chain from login to delete, and the two-user test for broken object level authorisation.
Key takeaways
- A rule enforced only in the UI is not enforced, because anyone can call the API directly.
- API tests run without a browser, so they are faster and less flaky than UI tests and a good place to learn a first language.
- Use Decimal, not floats, for money in tests and assertions.
- A chained API test follows the client's real sequence of calls and checks for a 404 after a delete to prove nothing was left behind.
- Broken object level authorisation only shows up when a second user requests the first user's resource; expect 403 or 404.
Contents
FAQ
Should a tester learn Python or TypeScript first?
Either works; pick the one your team's tests use and stay with it. Python with pytest suits API testing and scripting; TypeScript suits Playwright suites. This series uses Python.
What is a BOLA test?
A test for broken object level authorisation: log in as two users, create a resource as the first, request it as the second, and assert the API answers 403 or 404 instead of returning the data.
Why test the API if the UI already works?
The API is what every client calls, including someone with curl, so business rules and permissions must hold there. API tests also run faster and fail less often for reasons unrelated to the product.
Sources
Only you and the owner see your answer and rating. Send private feedback
Enjoyed it? Support fx-blog with a coffee.
Related posts
AI in Testing: Use It Without Trusting It, and Test AI Features
Trusting AI output gives you tests that can't fail and an assistant that invents policy. Review every AI-written test by breaking the feature on purpose, keep agents out of the gate, and test AI features with eval sets run in CI.
Quality Gates in CI: Make Your Tests Block a Bad Merge
Tests that run only when someone remembers put the gate in a person. Run them in four CI tiers that each block the next, keep the commit gate under ten minutes, give every run fresh data, and quarantine flaky tests the same day.
Green Tests, Broken Checkout: The Checks Functional Tests Miss
A green functional suite can't see a renamed field, a slow peak, an open security hole or a form a keyboard can't finish. Add a Pact contract, a k6 test against an SLO, a ZAP baseline scan, and axe plus a keyboard pass.
Comments
Oldest firstNo comments yet. Start the conversation.
Part 2 ended on BUG-311's 14:15 line: the API removed the code, and only the page got it wrong. You checked the API once, by hand. This part tests it every time, in code, without a browser.
The UI of the ShopLite checkout can hide the "Pay" button all it likes. Anyone with Postman can still send
POST /checkout. If the rule lives only in the page, it isn't a rule.The QA Skills Path, in seven parts:
One language, learned on the API
The repo's advice is short: learn one language before you automate anything. It has guides for Python, TypeScript, Java, C# and Go, and each ends with one real test. This series writes its code in Python 3.12 with pytest 8. Pick yours and stay with it.
The API is the right place to learn it. API tests run without a browser, so they are faster and less flaky than UI tests. They are also where business rules have to hold, because the API is what every client calls.
Your first test: the €50.00 edge
Part 2's boundary table becomes a parameterised test. The repo's version runs on its own, with a toy implementation of rule R3 in the same file:
Run it with
pip install pytest && pytest.parametrizeturns one test into two, and the third value gets its own test because it expects an error. NoteDecimal: testing money with floats is a boundary bug of its own, since0.1 + 0.2 != 0.3.Chain the checkout like a customer would
Testing one endpoint alone proves little. The repo's checklist chains the calls a real client makes, and the test fails if any link breaks:
The last call matters. A
404after the delete proves the record is gone, not left behind as a ghost row.Two users, one order
The checklist calls broken object level authorisation (BOLA) the most common API vulnerability: user A's order is readable by user B because the API never checks who owns it. You only find it with two users:
Both codes pass;
404also hides that the order exists. Write the same test for update and delete, and for every resource with an owner.Each remaining row of the repo's API checklist is one more test on the checkout:
POST /orderswithoutitems400with a readable message, not500"price": 0.01inPOST /cart/lines?limit=1000000429 Too Many RequestsTry it
The API is now covered, and it was never the problem: BUG-311 lives in the page, which shows €27.00 after the API has removed the code. A UI test has to wait for that total without
sleep(5), and the same checkout runs in the ShopLite app on two phones. Part 4, Why Your UI Tests Flake, and the Fix for Web and Mobile, builds UI tests that turn red only for a real reason.Read this with your AI