Write test cases
A test case is one scenario: a starting state, an input, and the result you expect. Writing the cases down before building the requests finds gaps while they are still cheap to fix, and gives others something to review.
The parts of a test case
| Field | What goes in it |
|---|---|
| ID | A short label, such as ORD-03 |
| Title | What is being checked, in a sentence someone else can read |
| Preconditions | What must be true first: signed in, an order exists |
| Request | Method, path, and the parts that matter: body, parameters, headers |
| Expected result | The status, and the values, headers or timing that must hold |
| Priority | High, medium or low |
Keep one case to one idea. "Create an order and check the stock and the email" is three cases.
Finding the cases
Four techniques find most of what matters. Use them in turn on each endpoint.
1. The happy path
One valid request with typical values. Always first: if this fails, nothing else matters.
2. Equivalence classes
Group inputs that the API should treat alike, and test one from each group. For a quantity that must be 1 to 10, the groups are: below the range, inside it, above it, and not a number. Four cases, not hundreds.
3. Boundaries
Bugs gather at the edges. For each limit, test the last valid value and the first invalid one. For 1 to 10: test 0, 1, 10 and 11.
Other edges worth a case: an empty string, an empty list, the longest allowed text, zero, a negative number, a date in the past.
4. What could go wrong
Walk down this list for every endpoint and note the ones that apply.
| Question | Expected answer, usually |
|---|---|
| A required field is missing? | 400 or 422, naming the field |
| A field has the wrong type? | 400 or 422 |
| The body is not valid JSON? | 400 |
| The id does not exist? | 404 |
| No credentials? | 401 |
| Valid credentials, someone else's data? | 403 or 404 |
| The wrong method? | 405 |
| The same request sent twice? | Depends: say what should happen |
| An unknown extra field? | Ignored, or 400: say which |
Worked example: POST /orders
From the Shop API sample. The rules: a token is required; the body needs productId and quantity; quantity may be at most 10.
| ID | Title | Preconditions | Request | Expected |
|---|---|---|---|---|
| ORD-01 | Place a valid order | Signed in | {"productId": 1, "quantity": 2} | 201; status is pending; id present |
| ORD-02 | Largest allowed quantity | Signed in | quantity: 10 | 201 |
| ORD-03 | Quantity over the limit | Signed in | quantity: 11 | 422; error is quantity_too_large; max is 10 |
| ORD-04 | Quantity far over the limit | Signed in | quantity: 50 | 422 |
| ORD-05 | Missing quantity | Signed in | {"productId": 1} | 400; error is validation_failed |
| ORD-06 | Empty body | Signed in | {} | 400 |
| ORD-07 | No token | Not signed in | Valid body, no Authorization | 401 |
| ORD-08 | Order can be read back | ORD-01 done | GET /orders/{id} | 200; same id |
| ORD-09 | Order can be cancelled | ORD-01 done | DELETE /orders/{id} | 204 |
| ORD-10 | Quantity of zero | Signed in | quantity: 0 | Undecided: ask |
ORD-10 is the valuable row. Writing the cases exposed a question the rules did not answer. Raising it now costs a message; finding it in production costs a refund.
From cases to requests
Each case becomes one saved request in ApiWorkbench:
| Case field | In ApiWorkbench |
|---|---|
| ID and title | The request name: ORD-03 Quantity over the limit |
| Preconditions | Earlier requests in the run, with captures |
| Request | Method, URL, Body, Params, Auth |
| Expected result | The Tests tab |
| The full case text | The Docs tab |
Group cases by endpoint or feature, in collections or in the folders of an imported collection. Cases that differ only in their input (ORD-01 to ORD-04) can become one request driven by a data file: see Data-driven testing.
Template
| ID | Title | Preconditions | Request | Expected | Priority |
|----|-------|---------------|---------|----------|----------|
| | | | | | |Reviewing a set of cases
Ask of the whole list:
- Is there a happy path for every endpoint in scope?
- Does every rule in the specification have a case on each side of it?
- Does every protected endpoint have a no-credentials case?
- Could each case fail? What would have to be wrong?
- Is anything expected "to work" without saying what working means?