Template
Test plan template
A copyable test plan template covering scope, approach, entry and exit criteria, environments, roles and risks. The short version teams actually keep updated.
A test case needs seven things: an identifier, an objective stating what it proves, the preconditions the system must be in, the exact test data, numbered steps each carrying its own expected result, the expected final state, and a recorded outcome. The per-step expected result is what separates a test case from a list of instructions, because it says where a run diverged rather than only that it did.
A test case is written once and run by somebody else, often months later, on a build nobody has seen yet. That is the constraint the format exists to meet. Anything the author knew and did not write down becomes a question at the moment the case is run, and the person running it usually resolves it by guessing.
In the template
Copy it as it is. There is no email step, and nothing on this page is behind one.
# Test case: [ID] [short name] ## Objective What this case proves, in one sentence. ## Traceability Requirement or acceptance criterion this case covers: ## Preconditions Account and role: Data that must already exist: Environment and build: ## Test data The exact values used, not a description of them. ## Steps | # | Action | Expected result | |---|--------|-----------------| | 1 | | | | 2 | | | | 3 | | | ## Expected final state What is true once the case passes. ## Cleanup What has to be reset before this case can run again. ## Result Status: Pass / Fail / Blocked Build or version: Run by: Date: Defect reference, if it failed:
# Test case: CHK-014 Apply a valid promo code at checkout ## Objective A valid promo code reduces the order total and leaves the order placeable. ## Traceability Requirement or acceptance criterion this case covers: PROD-412, criterion 3. ## Preconditions Account and role: standard customer, signed in, basket empty Data that must already exist: SKU-9931 in stock, promo code SPRING20 active Environment and build: staging, build 2.14.0 ## Test data Item SKU-9931 at 40.00. Promo code SPRING20, twenty percent off, no minimum, expires 2027-01-01. ## Steps | # | Action | Expected result | |---|--------|-----------------| | 1 | Add SKU-9931 to the basket | One item in the basket, total 40.00 | | 2 | Go to checkout, continue to payment | Payment step loads with the promo field visible | | 3 | Enter SPRING20 and press Apply | Discount line of 8.00, total 32.00, Place order enabled | ## Expected final state The order is placed, the total charged is 32.00, and SPRING20 is recorded as used once against this account. ## Cleanup Cancel the order and reset the promo code usage count for this account. ## Result Status: Fail Build or version: 2.14.0 Run by: QA lead Date: 2026-08-28 Defect reference, if it failed: CHK-014-D1
The template below is the field set that survives that handover. Each field removes one specific ambiguity, and the ones people skip are consistently the ones that make a failed run impossible to interpret.
Scroll the table sideways for the examples.
| Field | Why it earns its place | Example |
|---|---|---|
| ID and name | A stable identifier plus a short name. The identifier is what a defect report cites when the case fails, so it has to survive the case being edited. | CHK-014 Apply a valid promo code at checkout |
| Objective | One sentence saying what passing proves. If it cannot be written in one sentence, the case is testing more than one thing and should be two cases. | A valid promo code reduces the order total and leaves the order placeable. |
| Traceability | The requirement or acceptance criterion this case covers. It is what lets a release report that the criteria were checked rather than that the features were clicked, and it is the only field that answers which cases have to run again when a criterion is reworded. | PROD-412, criterion 3: a valid promo code reduces the order total and the order stays placeable. |
| Preconditions | The state the system must already be in: the account, its role, the data that must exist, the build. This is the field that turns a failure into a finding rather than into a question about setup. | Signed in as a standard customer with an empty basket, on build 2.14.0 in staging. |
| Test data | The exact values, not a description of them. "A valid promo code" is not test data, because the next person has to invent one and may pick one that behaves differently. | Item SKU-9931 at 40.00. Promo code SPRING20, twenty percent off, no minimum, expires 2027-01-01. |
| Steps | Each step is one action paired with what should be observable after it. A single expected result at the end tells you the case failed; per-step results tell you where. | 3. Enter SPRING20 and press Apply. Expected: a discount line of 8.00 appears and the total reads 32.00. |
| Expected final state | What is true when the case passes, stated separately from the last step. It catches the case that appears to work on screen and leaves the wrong thing in the database. | The order is placed, the total charged is 32.00, and the promo code is recorded as used once. |
| Cleanup optional | What has to be reset before the case can run again. A case that only passes on a fresh account and does not say so becomes flaky the second time somebody runs it. | Cancel the order and reset the promo code usage count for this account. |
| Result | Status, the build it ran against, who ran it, when, and the defect reference if it failed. Without the build, a pass from last week says nothing about today. | Fail on build 2.14.0, run by the QA lead on 2026-08-28. See CHK-014-D1. |
Not this
1. Apply a promo code at checkout. 2. Check the discount works.
This instead
Test data: item SKU-9931 at 40.00, promo code SPRING20, twenty percent, no minimum. 1. Add SKU-9931 to the basket. Expected: one item, total 40.00. 2. Continue to payment. Expected: the promo field is visible. 3. Enter SPRING20 and press Apply. Expected: a discount line of 8.00, total 32.00, Place order enabled.
A promo code is not test data, because the next person has to invent one, and they may pick a code with a minimum spend, which behaves differently and then fails for a reason that is not the bug. Check the discount works is not an expected result either: it tells you the case failed and never where it failed. Pairing every step with what should be observable after it is what turns a failure into a location.
The most common defect in a test case is scope. A case that signs a user in, adds an item, applies a code and completes payment will eventually fail, and its failure identifies four features at once. Splitting it means a failure names its own cause. The practical test is the objective sentence: if it needs an "and", the case needs splitting. The cost is more cases to maintain, and it is worth paying because a suite exists to localise faults, not to demonstrate that a journey works.
A case that passes for its author and fails for everyone else is almost always depending on state nobody wrote down: an account that already has a saved address, a feature flag left on, a record created during a previous run. Writing preconditions as things that must be true, rather than as steps to make them true, is what exposes that dependency. If the list is long, the case is coupled to a lot of setup and is a candidate for automation, where the setup can be created rather than assumed.
A recorded failure is only useful if somebody can act on it later, which means the result needs the build it ran against, the step it diverged at, and what was seen instead. A status of Fail with no build is untriageable, because the fault may already be gone. This is the same field set a bug report needs, and it is why a failed case should produce a defect reference rather than a note.
An identifier, an objective saying what passing proves, the preconditions the system must be in, the exact test data, numbered steps each with its own expected result, the expected final state, and a recorded outcome naming the build. The per-step expected results are what make a failure locatable.
A scenario names something to verify in one line, such as checking that promo codes apply correctly. A test case is the executable version of it: specific data, specific steps, a specific expected result. One scenario usually becomes several cases, one for each condition worth checking.
Detailed enough that somebody who has never used the feature can follow them without deciding anything. The test is whether two people running the case would take the same actions and compare against the same expected values. Vague data is the usual failure, because it lets two runs exercise different behaviour.
Writing them from the acceptance criteria, before or alongside the implementation, tends to find the ambiguities while they are still cheap to fix. Cases written afterwards describe what was built, which means they cannot catch the case where what was built was not what was asked for.
Template
A copyable test plan template covering scope, approach, entry and exit criteria, environments, roles and risks. The short version teams actually keep updated.
Template
A copyable UAT test plan template: scope, who signs off, the business scenarios to run, entry and exit criteria, and how a failure gets recorded.
Template
A copyable test strategy template with a filled-in example: product risks, test levels, environments, tools, roles, entry and exit rules, and review.
Environment, console and network attach themselves, on the free plan.