Designing test cases: boundaries, equivalence and negative tests
You cannot test every input, so you must pick the few that find the most bugs. Learn equivalence partitioning, boundary value analysis, negative tests, decision tables and state transitions with a real order API.
A quantity field accepts whole numbers from 1 to 10. How many values could a user type? Zero, negatives, decimals, text, a million, an empty box, emojis. The number is effectively endless, and you do not have time to try them all.
Test design is the skill of choosing a small set of tests that still finds most bugs. Weak testers try random things. Strong testers use a few simple techniques that tell them exactly which inputs matter. This lesson teaches those techniques with the Brew & Bean order API.
What a good test case looks like
A test case is a specific input, the steps to run it, and the result you expect, decided before you run it. Writing the expected result first stops you from rationalising whatever the system happens to do.
Anatomy of a test case
| Field | Example |
|---|---|
| ID | TC-07 |
| Title | Reject quantity above the maximum |
| Precondition | API running, menu has espresso |
| Steps | POST /orders with one line: espresso, qty 11 |
| Test data | customer_name Asha, phone 9876543210 |
| Expected result | 422 with message about quantity; no order created |
| Priority | High (affects money and kitchen load) |
A good title says the behaviour, not the mechanics: 'Reject quantity above the maximum', not 'Test qty 11'. When it fails in CI at 2 am, the title is the first thing anyone reads.
Technique 1: equivalence partitioning
Equivalence partitioning groups inputs that the system should treat the same way. If quantities 2, 3, 4 and 5 are all handled by the same code path, testing all four teaches you almost nothing extra. Test one value from each group.
For the quantity field (valid range 1 to 10), there are three groups:
Partitions for qty (valid range 1 to 10)
| Partition | Values | Expected | Pick one to test |
|---|---|---|---|
| Too low (invalid) | 0 and below | Rejected | -3 |
| Valid | 1 to 10 | Accepted | 5 |
| Too high (invalid) | 11 and above | Rejected | 25 |
Three tests instead of infinite ones. You can also partition non-numbers: type of input (number, text, empty, decimal) is another set of partitions. And partition other fields too. For the phone number: 10 digits starting with 6 to 9 (valid), starting with 0 to 5 (invalid), too short, too long, contains letters, empty.
Technique 2: boundary value analysis
Programmers make off-by-one mistakes constantly: writing < where <= was meant, or qty > 10 instead of qty >= 10. Bugs cluster at the edges of ranges. Boundary value analysis says: test exactly on each edge, and one step on either side.
Boundary values for qty
| Value | Position | Expected for qty (1 to 10) |
|---|---|---|
| 0 | Just below the lower edge | Rejected |
| 1 | Lower edge (smallest valid) | Accepted |
| 2 | Just above the lower edge | Accepted |
| 9 | Just below the upper edge | Accepted |
| 10 | Upper edge (largest valid) | Accepted |
| 11 | Just above the upper edge | Rejected |
Six tests cover the whole range better than twenty random ones. The rule is 'reject quantities above 10'. If the developer writes if qty >= 10: reject, then a valid order of exactly 10 is wrongly refused. Only a test on 10 reveals it. Random values like 5 or 7 pass either way.
Boundaries are everywhere, not only in numbers:
Boundaries beyond numbers
| Field | Rule | Boundary tests |
|---|---|---|
| customer_name | 1 to 50 characters | empty (0), 1 char, 50 chars, 51 chars |
| items | at least 1 line | 0 lines, 1 line |
| phone | exactly 10 digits | 9 digits, 10 digits, 11 digits |
| pickup time | shop open 8 am to 10 pm | 7:59 am, 8:00 am, 9:59 pm, 10:00 pm |
| total | sum of prices | smallest possible order (Filter Coffee x 1 = ₹80) |
Do not assume boundaries from the spec alone. Check how the code behaves. Is a pickup at exactly 10:00 pm allowed? The shop closes at 10, but 'open until 10 pm' is ambiguous. When a boundary is unclear, that is itself a finding. Ask the product owner, and write the answer into the test.
Technique 3: negative testing
Positive tests check that valid input works. Negative tests check that invalid input is refused safely: with a clear error, a right status code and no side effects. Many production bugs hide here, because developers naturally think about how the feature should be used, not how it will be misused.
Ideas for negative tests on any input:
A negative-testing checklist
| Idea | Example for POST /orders |
|---|---|
| Missing required field | No phone |
| Wrong type | qty is "two" or 2.5, items is an object, not a list |
| Empty or blank | customer_name is "" or just spaces |
| Too long | A 5,000-character name |
| Unknown value | item_id is pizza |
| Special characters | Name is <script>alert(1)</script>, or Ravi'; DROP TABLE orders;--, or an emoji |
| Wrong state | Cancel an order that is already picked up |
| Wrong identity | Read someone else's order id |
| Repeat or race | Send the same order twice quickly |
For every negative test, check three things: the status code is a 4xx (never 5xx), the message does not leak internals (no stack traces or database errors), and nothing was saved or changed.
Technique 4: decision tables
When several conditions combine to decide an outcome, use a decision table. Say Brew & Bean adds a rule: a coupon FIRST10 gives 10% off, but only on orders of ₹200 or more, and only once per customer.
Decision table for the FIRST10 coupon
| Rule | Order total ≥ ₹200? | First use of coupon? | Outcome |
|---|---|---|---|
| 1 | Yes | Yes | 10% discount applied |
| 2 | Yes | No | Coupon rejected: already used |
| 3 | No | Yes | Coupon rejected: minimum not met |
| 4 | No | No | Coupon rejected (either reason is acceptable; agree which message wins) |
Every row is a test case. The table makes it obvious when you have forgotten a combination, and rule 4 exposes a question for the developer that nobody had thought of. Add boundary tests on top: totals of exactly ₹199 and ₹200.
Technique 5: state transitions
Some things behave differently depending on their current state, like an order. Draw the allowed moves:
Order state transitions
| From state | Allowed next states |
|---|---|
| received | preparing, cancelled |
| preparing | ready, cancelled |
| ready | picked_up |
| picked_up | (none, final) |
| cancelled | (none, final) |
Then test every valid move, and several invalid ones such as received to ready, ready to cancelled, and anything out of picked_up. In this API, the invalid moves should return 409. For a table with 5 states there are 25 possible moves between states, so the table lets you check them all systematically.
Other useful techniques
| Technique | Idea |
|---|---|
| Error guessing | Use experience: where do bugs usually hide? Dates, time zones, empty lists, duplicates, very large input, slow networks, double clicks |
| Pairwise (all-pairs) | When many options combine (browser x phone x payment method), test every pair of values at least once instead of every combination, which cuts the test count a lot |
| Exploratory testing | Time-boxed, unscripted testing with a goal, such as 'explore what happens when payment fails'. Note what you try and what you find |
Putting it together: tests for POST /orders
Here is a compact plan for one endpoint, using the techniques above. Notice how few cases cover so much.
A test plan in about 25 cases
| Area | Test | Technique |
|---|---|---|
| Happy path | Valid order, 2 items | Equivalence (valid) |
| Quantity | 0, 1, 10, 11 | Boundary |
| Quantity type | "two", 2.5, null | Negative |
| Name length | 0, 1, 50, 51 characters | Boundary |
| Phone | 9 digits, 10 valid, 11 digits, starts with 5, has letters | Equivalence and boundary |
| Items | empty list, unknown id, duplicate item lines | Negative |
| Totals | check the maths for 1 item, many items, max qty | Functional |
| After failure | nothing saved, no 5xx, no stack trace | Negative |
How this comes up in interviews
'How would you test a login page / a textbox that accepts ages 18 to 60 / a lift?' is one of the most common QA interview questions. Do not just list random ideas. Say: 'I would use equivalence partitioning and boundary value analysis.' Then give the partitions, the boundary values (17, 18, 19, 59, 60, 61), negative cases (empty, text, negative, decimal), and mention non-functional checks (speed, security). Structure shows skill.
I am a tester. Act as a QA lead and list test cases for [feature or endpoint, e.g. POST /orders].
Rules of the feature: [list the rules, e.g. qty 1 to 10, phone is a 10-digit Indian mobile number].
Give a table with columns: ID, title, input, expected result, technique (equivalence, boundary, negative, state, decision table). Cover boundaries exactly. Then list 5 risky areas the rules do not mention and that I should ask the developer about.What to expect: Check that boundaries sit on the exact edge values, not near them. Remove duplicates that test the same partition. The 'questions to ask' list is often the most valuable part. Run a few cases for real before trusting the table.
Try it: Design tests for an age field
A signup form accepts ages from 18 to 60 (inclusive). List: (a) the equivalence partitions, (b) the boundary values to test, (c) five negative tests. Give the expected result for each.
Try it: Make a decision table
Brew & Bean offers free pickup scheduling only if the customer is logged in and the order total is at least ₹300. Build the decision table, then list the test cases including the boundary on the total.
Key takeaways
- A test case has data, steps and an expected result written before you run it.
- Equivalence partitioning: test one value from each group the system treats alike.
- Boundary value analysis: test on each edge and just either side, since off-by-one bugs live there.
- Negative tests check bad input gets a 4xx, a clear message and no side effects, never a 5xx.
- Decision tables handle combined rules; state tables handle things like order status.
- Interviewers want structure: name the technique, then list partitions, boundaries and negatives.
Check yourself
Finishing the quiz marks the lesson as done.
1. A field accepts quantity from 1 to 10. Which set is the best boundary-value test set?
2. What is the idea behind equivalence partitioning?
3. An invalid order request returns 500 with a stack trace in the body. Which is the best description?
4. When is a decision table most useful?
5. A shop is open 8:00 am to 10:00 pm. Which pickup times are the key boundary tests?
Saved on this device. Create a free account to keep it on every device.
Practise this with Sam
A real mock interview, out loud, with an honest scorecard. Free to start.