A consistent template turns test case writing from "every author invents a format" into "every author fills in a known structure." Consistency makes cases easier to write, easier to read, easier to review, and easier to maintain. The exact template matters less than the discipline of using one.
The standard fields
Write a test case for adding an item to cart
An e-commerce site lets users add products to their cart. Write a basic test case.
A widely used template includes:
- ID. A unique identifier (
TC-LOGIN-001,TC-CHECKOUT-042). Useful for cross-referencing in bug reports and traceability matrices. - Title. One line summarising the case. "Login with valid credentials redirects to dashboard."
- Module / area. Which part of the system this case belongs to. Used for filtering and reporting.
- Priority / severity. How important is this case in your test cycle?
- Preconditions. What must be true before the test starts? (User accounts, data state, environment.)
- Test data. Specific values used in the test. (Email, password, product IDs.)
- Steps. Numbered, atomic actions to perform.
- Expected results. What should happen at the end (and at any intermediate steps that need checking).
- Postconditions. What state the system should be in after the test, especially if the test cleans up after itself.
- Linked requirement. The user story, [requirement ID, or risk this case covers.
- Author / date. Who wrote it, when last updated.
Not every team uses every field, but the first eight are common almost everywhere.
Three common formats
1. Step / Expected pairs. Each step has an associated expected outcome. Useful for cases with multiple verification points.
| Step | Action | Expected result |
|---|---|---|
| 1 | Navigate to /login | Login form is visible |
| 2 | Enter valid email | Email field accepts input |
| 3 | Enter valid password | Password is masked |
| 4 | Click Sign In | URL changes to /dashboard within 2s |
2. Given / When / Then (BDD style). Inspired by behaviour-driven development:
Given I am on the login page And I have a valid account
qa@example.com / Pass1234!When I enter the email and password And click Sign In
Then I am redirected to /dashboard within 2 seconds And my display name appears in the header
This format reads like a story. It is favourite for cases that will be automated with frameworks that support BDD (Cucumber, SpecFlow).
3. Action-based prose. A short paragraph followed by an expected result. Useful for simple cases where step/expected pairs would be overkill:
Log in as a Pro user from the EU region. Open the billing page. Verify that prices are displayed in euros and include VAT.
Mixing formats is fine. Use whichever fits the case. Force-fitting a one-line check into Given/When/Then makes the case longer without making it clearer.
Where to store test cases
Common options:
- Test management tools. TestRail, Zephyr Scale, Xray, qTest. Best for teams with formal test cycles, traceability needs, or compliance requirements.
- Markdown / wiki pages. Confluence, Notion, GitBook. Lightweight, version-controlled if in a repo, easy to link from tickets.
- In the codebase. For automated cases, the code itself is the canonical source of truth. The test name and description should be self-explanatory.
- Spreadsheets. Surprisingly common. Easy to create, hard to maintain at scale. Avoid except for very small projects.
The "best" location is the one your team actually reads and updates. A pristine TestRail nobody opens is worse than a messy markdown file everyone references.
Naming conventions
Consistent naming pays off in big test suites:
- Format:
<feature>_<condition>_<expected>is widely used. Example:login_validCredentials_redirectsToDashboard. - Use the present tense. "Login redirects to dashboard" reads better than "Login redirected to dashboard."
- Avoid bare verbs. "Test login" tells you nothing. "Login with empty password shows error" is informative.
- Match the requirement vocabulary. If the spec calls it "Sign in," do not call it "login" in the case. Drift causes confusion.
Good names mean a developer can look at a list of test names and instantly understand what is covered without reading the cases themselves. That is a powerful debugging aid when triaging failures.
Keeping cases alive
Test cases rot. Features change, language evolves, links break. A few habits help:
- Review cases when the corresponding feature changes. Update or delete affected cases as part of the change.
- Periodically prune. Once a quarter, delete cases for removed features or that have not been run in years.
- Tag flaky cases. If a case keeps failing intermittently, fix or quarantine it — do not let it train the team to ignore failures.
- Pair new cases with existing ones. When you write a new case, search for similar existing cases to avoid duplication.
What you should walk away with
A consistent template turns test case writing into a fill-in-the-blanks exercise instead of a creative one. Pick a template, name cases predictably, and put them somewhere the team actually opens. The next lesson tackles the most common axis along which to vary cases: positive, negative, and edge cases.