API Testing Best Practices
Over this track you've built a real Postman workflow around the RecipeBox API: requests, collections, environments, assertions, chaining, pre-request scripts, authentication, schema validation, the Collection Runner, Newman, and mock servers. This last lesson isn't a new tool — it's a checklist of habits that separate a test suite that stays useful for years from one that quietly rots after a few months. Keep this page bookmarked; it's meant to be revisited, not just read once.
1. Test the Happy Path AND the Error Cases
It's tempting to write one test per endpoint that checks the "it worked" case and move on. That leaves the entire error-handling half of the API completely unverified. For every RecipeBox endpoint, deliberately test the failure paths too:
| Status | Example RecipeBox case to test on purpose |
|---|---|
| 400 | POST /recipes with no title in the body |
| 401 | POST /recipes sent with no Authorization header, or an expired token |
| 404 | GET /recipes/999999 for an id that doesn't exist |
| 422 | POST /recipes with prepMinutes set to -5 (wrong type/shape is valid JSON but semantically invalid) |
| 500 | Hard to trigger deliberately, but if you ever see one unexpectedly from a valid request, that's a bug worth its own report — never a test failure to just retry away |
A collection with as many "should fail correctly" requests as "should succeed" requests is a sign of a thorough tester, not a pessimistic one — an API that returns the wrong status code on bad input is exactly the kind of bug a UI-only test pass would never catch.
2. Never Hardcode Data That Can Collide Between Runs
A test that creates a recipe titled "Test Recipe" works the first time. Run the same
collection again — in CI, or because someone re-ran it manually — and now there are two recipes
with that exact title, and a test asserting "exactly one recipe matches this title" starts
failing for reasons that have nothing to do with a real bug. Generate unique values instead:
// Pre-request script on "Create Recipe"
pm.collectionVariables.set("uniqueTitle", "Test Recipe " + Date.now());
POST {{baseUrl}}/recipes
Content-Type: application/json
{
"title": "{{uniqueTitle}}",
"ingredients": ["flour", "sugar"],
"steps": ["Mix", "Bake"],
"category": "Dessert",
"prepMinutes": 15,
"isPublished": false
}
Postman's built-in dynamic variables ({{$randomUUID}}, {{$timestamp}},
{{$randomInt}}) work just as well for this and need no script at all. Either way, the
goal is the same: a run today shouldn't be able to collide with leftover data from a run
yesterday.
3. Keep Secrets Out of Version Control
A collection exported for Newman/CI, or shared with teammates, can easily end up committed to a git repository. If a real password or bearer token is typed directly into a request body or a committed environment file, it's now in your git history — even deleting it later doesn't remove it from old commits.
- Store
token,password, and API keys as environment variables, never typed directly into a request. - Mark sensitive variables as type secret in Postman so they're masked in the UI and excluded from synced/shared views by default.
- When exporting an environment for Newman/CI, keep real secret values in the CI system's own secret store (e.g. GitHub Actions secrets, Jenkins credentials) and inject them at run time with
--env-varrather than baking them into the committed JSON file.
newman run recipebox-collection.json -e dev-environment.json --env-var "token=$RECIPEBOX_TEST_TOKEN"
4. Test Response Time, Not Just Correctness
A response can be perfectly correct and still be a problem if it's slow. Assert on response time the same way you assert on status and body:
pm.test("response time is under 500ms", function () {
pm.expect(pm.response.responseTime).to.be.below(500);
});
This won't catch every performance problem — that's what dedicated load testing tools are for — but it catches an endpoint that's quietly regressed from 80ms to 3 seconds long before a user complains, and it costs one extra line per request.
5. Organize Collections Into Logical Folders
A flat list of forty requests is hard to navigate and hard to run selectively. Group RecipeBox requests by feature, the same way you'd organize test cases:
RecipeBox API/
Auth/
Login
Login - invalid password (401)
Recipes/
Create Recipe
Create Recipe - missing title (400)
Get Recipe by ID
Get Recipe by ID - not found (404)
Search Recipes
Recipes/Schema Validation/
Get Recipe by ID - schema check
Folders also let the Collection Runner and Newman target just one feature area
(newman run recipebox-collection.json --folder Auth) instead of the whole suite —
useful when you only need a fast sanity check on one area, not a full regression pass.