Reusable and Regression Test Cases
A reusable test case is written once and run many times, with different data and in different suites. You write the steps once, put the values that change into a data table, and keep common set-up, such as logging in, in one shared block. A regression test case is one that has earned a place in the regression suite: the cases re-run after changes to check that what worked before still works.
For example, a shop lets a customer add 1 to 10 units of an item to the cart. The one-off approach writes four cases for 1, 10, 0 and 11 units, each repeating the log-in steps. The reusable approach writes one case, "Add <qty> units to the cart", with a table of quantities and expected results.
Why it matters
Test cases are run far more often than they are written. Copied steps drift apart: one copy is updated, three are not, and the suite fails for reasons that are not defects. Reusable cases keep each step and each value in one place, so a new log-in screen or a new limit is changed in one place.
A regression suite helps only while the team trusts it and can afford to run it. A suite that only grows fills with duplicates and cases for removed features, becomes too slow and is skipped when time is short, which is exactly when it is needed.
From one-off to reusable test cases
A one-off test case mixes three things: the steps that check a behaviour, the data values and the set-up the steps need. That is fine for a check you run once, and expensive as soon as the case is copied for another value.
A reusable test case keeps the three apart. In ISTQB glossary terms, the case written with placeholders is a high-level (logical) test case: its inputs and expected results are abstract. Each row of concrete values in its table makes a low-level (concrete) test case, with its own expected result and its own pass or fail.
- Parameterised: the steps contain placeholders such as
<qty>instead of fixed values. - Data-driven: a table of values and expected results drives the runs, one row per run.
- Shared steps: set-up that many cases need, such as logging in, is written once and referenced by its ID.
One-off test cases
Four cases, one per quantity: 1, 10, 0 and 11
- Steps:
- Written out again in every case
- Values:
- Fixed inside the steps
- Log-in and product set-up:
- Copied into every case
- Adding a value such as 2.5:
- Copy a whole case and edit it
- The limit changes from 10 to 20:
- Find and edit every case that uses or names the limit
- The log-in page changes:
- Edit every case
- Results recorded:
- One per case
Reusable test case
TC-CART-010 with <qty>, a data table and shared block SS-01
- Steps:
- Written once
- Values:
- One row per value in a data table, tagged by type
- Log-in and product set-up:
- Shared block SS-01, referenced by its ID
- Adding a value such as 2.5:
- Add one row
- The limit changes from 10 to 20:
- Edit the table only: 20 and 21 replace 10 and 11
- The log-in page changes:
- Edit SS-01 only
- Results recorded:
- One per row
Worked example: one case, many data rows
Requirement: "A customer can add 1 to 10 units of an item to the cart. If fewer units are in stock than requested, nothing is added and a message says how many are left." Each row below has a type tag and its own expected result, with the messages taken from the screen design; stock is a column because one row needs a different value.
Run the case row by row and record one result per row. If the limit changes from 10 to 20, you edit only the table: 20 and 21 replace 10 and 11, and the messages name the new limit; the steps stay the same. Saved as a CSV file (comma-separated values: a plain-text table with one row per line), the same table can feed an automated test: the ISTQB glossary describes data-driven testing as a scripting technique that keeps test data and expected results in data files used by the test scripts.
TC-CART-010 Add <qty> units of a product to the cart
Precondition: SS-01 Log in as a customer and open product P-200
(stock level as in the row)
Steps: 1. Enter <qty> in the Quantity field
2. Select "Add to cart"
Expected: <expected>
Row Type qty stock expected
R1 positive 3 50 added: cart shows 3 x P-200
R2 boundary 1 50 added: cart shows 1 x P-200
R3 boundary 10 50 added: cart shows 10 x P-200
R4 boundary 0 50 refused: "Enter a quantity from 1 to 10"
R5 boundary 11 50 refused: "You can add at most 10 units"
R6 negative 2.5 50 refused: "Enter a whole number", cart unchanged
R7 edge (empty) 50 refused: "Enter a quantity from 1 to 10"
R8 edge 5 4 refused: "Only 4 left in stock", cart unchangedPositive, negative, boundary and edge cases in one suite
Tagging every row with its type makes gaps visible: if all the rows are positive, the suite proves only the happy path, however many rows it has. Balance does not mean equal numbers; it means every rule has its accepted and its refused side covered. For the quantity rule:
- Positive: valid input and intended use, such as 3 units. The item is added.
- Negative: invalid input, such as 2.5. It is refused with a clear message and the cart does not change.
- Boundary: the smallest and largest allowed values and their neighbours just outside: 1, 10, 0 and 11.
- Edge: one input or condition at an extreme, such as an empty field, or an item almost sold out: 4 left when 5 are requested.
Try it: Boundary Number Dataset Generator Try it: Negative Test Generator
Building and maintaining a regression suite
The lesson on confirmation and regression testing showed how to choose which tests to run after a change; this section is about the suite itself. A case belongs in it when it protects behaviour that must keep working and its expected result is stable. Tag each case with a tier, such as core for every build and full for the nightly run, guided by its priority, and review the suite at a fixed point, such as the end of each release.
- Promote: critical journeys, high-priority rules, areas that broke before, and a case for each fixed defect the suite did not already cover.
- Leave out: one-time checks and duplicates. Cases for a feature that still changes every sprint wait until its behaviour settles.
- Update: when a requirement changes, update the affected expected results in the same sprint as the code.
- Merge and retire: cases that check the same behaviour become one; cases for removed features are archived with the reason.
- Repair: a case that fails without a product defect, because of unclear steps or unreliable data, is fixed promptly.
Try it: Regression Scenario Generator Try it: AI Duplicate Test Case Detector
Common mistakes
- Copying a case to change one value, instead of adding a row to its data table.
- Writing expected results such as "works correctly", so a row cannot be judged pass or fail.
- Filling a table with positive rows only, or with many rows that all test the same thing.
- Adding every new case to the regression suite and never updating, merging or retiring any.
- Leaving the test for a fixed defect in the closed bug report instead of making it a regression case.
The QA perspective
Before you write a shared block, check whether one already exists, and agree with the other testers on ID prefixes (TC-, SS-), type tags and tier tags. Involve whoever automates the tests: a good data table can become the data file of an automated test with little change.
For each regression case, record why it is in the suite (a critical journey, a past defect, a business rule), its owner and the date of its last review. At the end of a release, go through what changed with the developers and the product owner, then update, merge and retire cases.
Practice exercise
Turn copied coupon cases into one reusable case
The cases below were written by copying. Rewrite them as one shared step block and one parameterised case with a data table, add the missing rows, and decide what happens to each original case in the regression suite.
Rule: SAVE10 gives 10% off orders of 50.00 SAR or more. Codes are not
case-sensitive. Expired codes, such as OLD5, are refused.
TC-41 Log in, add items worth 200.00, open cart, apply SAVE10 -> 20.00 off
TC-42 Log in, add items worth 49.99, open cart, apply SAVE10 -> refused
TC-43 Log in, add items worth 200.00, open cart, apply OLD5 -> refused
TC-44 Log in, add items worth 200.00, open cart, apply save10 -> 20.00 off
TC-45 Log in, add items worth 200.00, open cart, apply SAVE10 -> 20.00 off
TC-46 Log in, add gift wrap to an order -> gift wrap added
(gift wrap was removed from the product in release 4.2)- Write the shared block for the set-up every case repeats, ending with a checkpoint.
- Write one parameterised case and turn TC-41 to TC-45 into rows with type tags and expected results.
- Add the rows a balanced suite still lacks.
- For each original case, decide: keep it as a row, merge it or retire it, and choose the tier.
Show the model answer
Shared block SS-07: log in as a customer, add items worth <cart> SAR, open the cart. Checkpoint: the cart total shows <cart>.
TC-COUPON-01 "Apply <code> to a cart of <cart> SAR". Rows: positive, 200.00 with SAVE10, 20.00 off; boundary, 49.99 with SAVE10, refused (minimum order); negative, 200.00 with OLD5, refused (expired); positive, 200.00 with save10, 20.00 off.
Missing rows: boundary, 50.00 with SAVE10, 5.00 off; negative, an unknown code such as ABC123, refused; edge, an empty code, refused; negative, SAVE10 applied a second time to the same cart, the discount stays 20.00 and is not doubled. The rule does not say which message the second attempt shows, so ask the product owner.
Suite: TC-41 to TC-44 become rows; TC-45 repeats TC-41 and is merged; TC-46 is retired with the reason "gift wrap removed in 4.2". TC-COUPON-01 goes into the core tier: it changes what customers pay.
Frequently asked questions
Is a parameterised test case the same as an automated data-driven test?
They share the idea: steps written once, values in a table. A person runs a parameterised manual case row by row; in automation, data-driven testing means the script reads the rows from a data file such as a CSV. A table designed well for manual runs can usually be reused as that data file.
Should every test case go into the regression suite?
No. The regression suite holds the cases that protect behaviour which must keep working: critical journeys, important rules and past defects. One-time checks and duplicates stay out, and cases for a feature that still changes every sprint wait until it settles; otherwise the suite becomes too slow to run after every change.
How often should a regression suite be reviewed?
At a fixed point, such as the end of every release or sprint, and whenever a requirement changes. Waiting until the suite is too slow or too unreliable means the team has already stopped trusting it.
References
- ISTQB GlossaryThe standard definitions of testing terms — test case, regression testing, severity, priority, boundary value analysis and the rest.
- ISTQB Certified Tester Foundation Level (CTFL) v4.0The foundation syllabus of software testing: test levels and types, test design techniques, test management and tools.
Practise with Mutqan tools
Generate structured test cases (id, title, preconditions, steps, expected result, priority) from a feature description and field list.
Generate CSV files with custom columns, data types, row counts and delimiters.
Generate boundary values around limits: min-1, min, min+1, max-1, max, max+1 for integers of any width.
Generate negative test cases for form fields and APIs: empty, null, wrong type, too long, injection, invalid format.
Generate regression scenarios from a change description and a list of affected and related modules.
Find duplicate and overlapping test cases in a suite and get merge recommendations from Mutqan AI.
Go deeper
Your progress on this topic
Not started
Mark the topic complete when you have studied it and done the exercise.
Sign in to track your progress
Mark topics complete, continue where you left off and unlock specialisation exams.