Positive and Negative API Testing
Confirming an API does what it should is only half the job. Negative testing confirms it correctly refuses what it shouldn't allow.
What you'll learn
- Distinguish positive test cases from negative test cases for a given endpoint
- Design negative test cases covering missing fields, wrong types, and invalid values
- Explain why a negative test that receives a 200 response indicates a real defect
Prerequisites
Explanation
Positive testing confirms the API does the right thing with valid input: create a user with a well-formed request, and it should succeed with a 201 and the expected data back. This is the testing most people write first, and it's necessary — but it only proves the API works when everything is done correctly, which is not how real usage looks. Negative testing confirms the API correctly rejects invalid input, and it's just as necessary, arguably more so: a broken create-user endpoint that silently accepts a request missing the required email field will store bad data that breaks something else later, somewhere far from where the mistake happened.
A thorough set of negative test cases for a single endpoint typically covers: a missing required field (send the request without email — expect a 400, not a 200 with a null email silently stored); a wrong type (send age: "twenty-five" instead of a number — expect a 400, not the string silently accepted or coerced unpredictably); an invalid value within the right type (send age: -5, a number, but not a sensible one — expect a 400, since type-correctness alone isn't validity); and malformed input entirely (send a request body that isn't valid JSON at all — expect a clean 400, not a 500 crash).
Here's the sharpest, most important idea in this lesson: when a negative test case receives a success response, that is not a passing test — it's the discovery of a real defect. A tester who runs POST /users with no email field and gets back 201 Created has not confirmed the API is lenient; they've found proof the API accepts genuinely broken data into the system, which will eventually cause failures somewhere downstream, at a much less convenient time and place to diagnose.
Example
A simulated user-creation validator, tested with one positive and three distinct negative cases — all deterministic, no real network call.
function validateNewUser(payload) {
if (typeof payload.email !== "string" || payload.email.length === 0) {
return { status: 400, error: "email is required and must be a non-empty string" };
}
if (typeof payload.age !== "number" || payload.age < 0) {
return { status: 400, error: "age must be a non-negative number" };
}
return { status: 201, body: { id: 1, ...payload } };
}
console.log(validateNewUser({ email: "a@b.com", age: 25 })); // positive: 201
console.log(validateNewUser({ age: 25 })); // negative: missing email
console.log(validateNewUser({ email: "a@b.com", age: -5 })); // negative: invalid valueTry it yourself
Add a fourth call testing a wrong-type age (a string like "25") and predict the result.
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Guided exercise
Guided exercise
Using the validateNewUser function already defined, run three cases and store their status codes: statusPositive (valid input), statusMissingEmail (no email field), statusNegativeAge (age is -1).
Checks: positive case returns 201 · missing-email negative case returns 400 · negative-age negative case returns 400
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Independent exercise
Independent exercise
Write a function flagFalsePositive(testCaseIsNegative, actualStatus) that returns true if a negative test case (testCaseIsNegative is true) unexpectedly received a success status (2xx) — meaning the API wrongly accepted invalid input. Return false in every other combination.
Checks: flags a negative test case that wrongly succeeded · does not flag a correctly-rejected negative case · does not flag a correctly-succeeding positive case
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Common mistakes
- Writing only positive test cases and treating "it works with good data" as complete coverage.
- Treating a negative test case that unexpectedly returns 200 as a passing test instead of a discovered defect.
- Testing only one kind of invalid input (e.g. only missing fields) and skipping wrong types and invalid-but-correctly-typed values.
Knowledge check
Takeaway
Negative testing is not optional polish — it verifies the API correctly rejects invalid input, and a negative test case that unexpectedly succeeds has found a real defect, not passed.
Summary
This lesson covered the categories of negative test cases (missing fields, wrong types, invalid values) and the key insight that a negative case receiving a success response is a discovered defect.
References
Your notes
Notes save automatically.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.