A copy-paste ready template for writing formal test cases — with field-by-field guidance, good vs. bad examples, and a fully worked NZ scenario.
1 What this covers
A formal test case is a structured, reusable record that documents exactly what to test, how to test it, and what to expect. It is not the right tool for every situation. Use it when:
You need an audit trail — e.g. regulated industries (financial services, health), government systems, or any project requiring compliance sign-off.
The same test will be run multiple times across releases or by different testers, and you need consistent results.
A step-by-step regression suite is handed to another team or an offshore partner who cannot rely on tribal knowledge.
A stakeholder or client requires documented evidence of test coverage (e.g. ACC, Inland Revenue, or a council system).
When not to use a formal test case:
Exploratory sessions — use a charter and session notes instead. The discovery mindset is lost if you pre-script every step.
Fast-moving prototype work where the UI changes weekly — maintenance cost exceeds value.
Simple smoke checks that are self-evident (“does the page load”).
Rule of thumb: If the test needs to be repeated reliably by someone who was not in the room when the feature was built, write a formal test case. Otherwise, an exploratory note is lighter and faster.
2 The Template
Copy the block below into your test management tool (TestRail, Zephyr, Xray, a spreadsheet, or a plain document). Every field is explained in the Field Guide below.
Test Case ID : TC-[MODULE]-[NNN]
Title : [Brief description of what is being verified]
Preconditions :
- [System state required before the test starts]
- [User account / role / data required]
- [Any dependent feature that must already work]
Test Steps :
1. [Action]
Expected : [What should happen immediately after step 1]
2. [Action]
Expected : [What should happen immediately after step 2]
3. [Action]
Expected : [What should happen immediately after step 3]
(add or remove steps as needed)
Expected Result : [The overall pass condition — what success looks like at the end]
Actual Result : [Filled in during execution — what actually happened]
Status : [ ] Pass [ ] Fail [ ] Blocked [ ] Not Run
Notes : [Defect IDs, environment quirks, screenshots attached, assumptions made]
Tester : [Name / initials]
Date Executed : [DD MMM YYYY]
3 Field Guide
Each field has a job. Weak fields are the most common cause of tests that produce ambiguous results or cannot be re-run by someone else.
Field
Purpose
Good example
Bad example
Test Case ID
Unique identifier so the case can be referenced in defect reports and traceability matrices.
TC-KS-042
Test 1 or left blank
Title
One-line description of the scenario being verified. Should name the feature, the action, and the key condition.
Employer KiwiSaver rate change: 3% to 6% saves correctly
Test KiwiSaver
Preconditions
Everything that must be true before step 1 runs. Missing preconditions are the top cause of unreproducible failures.
Logged in as employer with IRD number 123-456-789; employee record exists with current rate 3%; test environment pointing to UAT stub for IRD gateway.
User is logged in
Test Steps
Numbered actions a tester performs. Each step should be a single, unambiguous action, not a paragraph.
1. Navigate to Employee → Contribution Settings 2. Click the Employer Rate field and change value from 3 to 6
1. Go to KiwiSaver settings and update everything
Expected Result (per step)
What the system should do immediately after each step. Inline expected results catch defects at the exact point of failure rather than at the end.
Step 2 Expected: Field accepts numeric input; no validation error shown
Step 2 Expected: Works
Expected Result (overall)
The final pass condition — the state the system should be in at the end of all steps.
Contribution rate displays as 6% on Employee Summary; audit log records the change with tester username and timestamp; no error email sent to IRD gateway.
KiwiSaver rate is updated
Actual Result
Filled in only during execution. Describes exactly what happened — including error messages verbatim.
Rate displayed as 6% on summary. Audit log entry created at 14:32 NZST. No gateway error.
It worked / It failed
Status
The outcome of execution. Blocked means the test could not run due to an external dependency, not that it failed.
Pass / Fail / Blocked / Not Run
OK / Done / N/A
Notes
Anything a future tester needs to know: defect IDs, environment gotchas, screenshots, workarounds applied, or assumptions that were made.
DEF-214 raised. Screenshot attached. RealMe login stub used — real credential check not available in UAT.
Left blank
Tester / Date
Accountability and traceability. Required for regulated projects and useful for spotting if a tester pattern-matched rather than actually executing.
S. Tahi — 27 Jun 2026
Left blank
NZ context: Government and financial services projects in Aotearoa regularly require test evidence for sign-off. RealMe login flows, IRD gateway integrations, and ACC claim submissions are common precondition items. Always name the stub or gateway environment in your preconditions so a future reader knows whether the test ran against a real or mocked dependency.
4 Worked Example
A KiwiSaver employer portal allows employers to update the voluntary employer contribution rate for an employee. The following test case verifies that changing the rate from 3% to 6% is saved, displayed, and logged correctly.
Fully filled test case
Test Case ID : TC-KS-042
Title : Employer KiwiSaver contribution rate change: 3% to 6% saves and audits correctly
Preconditions :
- Logged in as employer user role (IRD number 123-456-789) in UAT environment
- Employee record "Jamie Ngata (EMP-0091)" exists with current employer rate set to 3%
- IRD gateway is pointed at UAT stub (no real submissions will be sent)
- Browser: Chrome 126, screen width 1440px
- No pending rate changes exist on this employee record
Test Steps :
1. From the dashboard, navigate to Employees → EMP-0091 (Jamie Ngata).
Expected : Employee profile page loads with "Current employer rate: 3%" displayed
in the Contribution Settings card.
2. Click the "Edit" button next to Contribution Settings.
Expected : Inline edit mode activates; the Employer Rate field becomes an editable
numeric input pre-filled with "3".
3. Clear the field and type "6".
Expected : Field shows "6"; no validation error is shown; a helper text reads
"Minimum employer rate: 3% (compulsory). You are entering a voluntary rate."
4. Click "Save Changes".
Expected : A confirmation modal appears: "Update employer contribution rate for
Jamie Ngata from 3% to 6%? This will take effect from the next payroll run."
5. Click "Confirm" in the modal.
Expected : Modal closes; page reloads; Contribution Settings card shows
"Current employer rate: 6%". A green toast notification reads
"Contribution rate updated successfully."
6. Navigate to Admin → Audit Log and filter by employee EMP-0091.
Expected : Most recent entry shows:
Action: CONTRIBUTION_RATE_CHANGE
Changed by: [current tester username]
Old value: 3% | New value: 6%
Timestamp: within 60 seconds of step 5
Expected Result : Employer contribution rate for Jamie Ngata is updated to 6% and
persisted in the database. The audit log captures the change with
correct user attribution and timestamp. No gateway error is generated.
The change is visible immediately on the employee profile without
requiring a page hard-refresh.
Actual Result : [Filled in during execution]
Status : [ ] Pass [ ] Fail [ ] Blocked [ ] Not Run
Notes : IRD gateway stub used — real submission not tested here.
See TC-KS-043 for gateway error handling.
Payroll cut-off logic is out of scope for this case (see TC-KS-050).
Tester : S. Tahi
Date Executed : 27 Jun 2026
5 Variations
The base template above is format-agnostic. The same information can be expressed in different styles depending on what your team or tool requires.
ISTQB Formal
ISTQB-aligned test case format
Adds explicit traceability fields used in test management tools like TestRail or Zephyr. Required for CTFL-aligned test plans.
Test Case ID : TC-[MODULE]-[NNN]
Requirement ID : [REQ-NNN or User Story ID — links this case to a business requirement]
Priority : [High / Medium / Low]
Test Type : [Functional / Regression / Smoke / UAT]
Title : [Description]
Preconditions : [...]
Test Steps : [numbered steps with inline expected results]
Expected Result: [overall pass condition]
Actual Result : [execution notes]
Status : Pass / Fail / Blocked / Not Run
Tester : [Name]
Date : [DD MMM YYYY]
Reviewed by : [Lead QA name — required for ISTQB test deliverable sign-off]
BDD / Gherkin
Given / When / Then format
Used when tests are automated with Cucumber, Playwright BDD, or SpecFlow. Written in plain language so product owners can read and verify scenarios. The same KiwiSaver example in Gherkin:
Feature: Employer KiwiSaver contribution rate management
Background:
Given I am logged in as an employer with IRD number 123-456-789
And employee "Jamie Ngata" (EMP-0091) has a current employer rate of 3%
And the IRD gateway is configured to use the UAT stub
Scenario: Successfully update employer contribution rate from 3% to 6%
When I navigate to the Contribution Settings for employee EMP-0091
And I change the employer rate from "3" to "6"
And I confirm the change in the confirmation modal
Then the Contribution Settings card should display "Current employer rate: 6%"
And the audit log should contain a CONTRIBUTION_RATE_CHANGE entry for EMP-0091
And the audit log entry should record the old value as "3%" and new value as "6%"
And no IRD gateway error should be generated
Scenario: Reject an employer rate below the compulsory minimum of 3%
When I navigate to the Contribution Settings for employee EMP-0091
And I change the employer rate to "2"
Then a validation error should display "Minimum employer rate is 3% (compulsory)"
And the Save button should be disabled
Exploratory Note
Session-based exploratory note
Not a test case — a lightweight record for exploratory sessions. No numbered steps. Captures charter, time-box, observations, and follow-ups. Use this when you are discovering behaviour, not re-running a known script.
Charter : Explore the KiwiSaver rate change flow for employer users.
Focus on edge cases: decimal values, rates below 3%, concurrent edits.
Tester : S. Tahi
Session Start : 27 Jun 2026, 14:00 NZST
Duration : 60 minutes (time-boxed)
Environment : UAT — Chrome 126
Observations :
- Rate accepts decimals (e.g. 3.5%) but the UI rounds display to 2dp. Spec is silent on this — flag for BA.
- Entering "abc" in the rate field: no validation error on blur, only on Save. Possible DEF candidate.
- Concurrent edit: opened two browser tabs, changed to 6% in tab 1 and 5% in tab 2.
Tab 2 save silently overwrote tab 1 — no conflict warning. Raised DEF-219.
- Audit log truncates usernames over 32 chars — tester "brendon.testaccount@example.com" shows as "brendon.testaccount@ex".
Defects Raised : DEF-219 (concurrent edit overwrites silently)
Follow-up Tests: TC-KS-044 (decimal rate values), TC-KS-045 (concurrent edit conflict handling)
6 Common Mistakes
1 — No preconditions
A test case without preconditions cannot be reproduced reliably. The tester who wrote it knows what setup they did implicitly. Everyone else gets inconsistent results and blames the test. Write preconditions as if handing the test to someone who has never seen the system.
2 — Vague expected results
"The page updates correctly" is not an expected result. Specify exactly what should change: which element, what text, what value, within what time. "The Contribution Settings card displays 'Current employer rate: 6%' without a page hard-refresh" is testable. "Correctly" is not.
3 — Testing multiple things in one case
A single test case that checks rate update, audit log, email notification, payroll integration, and error handling is impossible to triage when it fails. One scenario per case. If the rate update passes but the audit log fails, you need separate cases to isolate which is failing.
4 — Step-result mismatch
A test with 6 steps and only one overall expected result at the end misses defects mid-flow. If step 3 produces a subtle wrong state that only manifests at step 5, you will not know where the defect is. Add an inline expected result to every step that changes system state.
5 — Missing negative tests
Most test suites are heavy on happy path and light on failure scenarios. For every acceptance criterion ("user can update the rate"), write at least one negative case ("user cannot set rate below 3%", "user cannot set rate to a non-numeric value"). The compulsory KiwiSaver minimum is exactly the kind of business rule that breaks under negative input.
7 Copy-Paste Block
Clean Markdown version suitable for pasting into Confluence, Notion, GitHub Issues, or a plain text file.
## Test Case: [Title]
**ID:** TC-[MODULE]-[NNN]
**Date:** DD MMM YYYY
**Tester:** [Name]
**Status:** Pass / Fail / Blocked / Not Run
### Preconditions
- [System state required before step 1]
- [User account / role / data]
- [Environment / stub / dependency details]
### Test Steps
| Step | Action | Expected Result |
|------|--------|-----------------|
| 1 | [Action] | [What should happen] |
| 2 | [Action] | [What should happen] |
| 3 | [Action] | [What should happen] |
### Overall Expected Result
[Final pass condition — system state at end of all steps]
### Actual Result
[Filled in during execution]
### Notes
[Defect IDs, screenshots, assumptions, environment quirks]