How to Write Test Cases for Gift Cards (With Examples)
How to Write Test Cases for Gift Cards (With Examples)
How to Write Test Cases for Gift Cards (With Examples)
Gift card functionality is a common feature in e‑commerce, retail, and gaming platforms, yet it hides a surprising amount of complexity. A single card can be purchased, redeemed, reloaded, transferred, expired, or fraudulently tampered with, and each of those paths touches payment gateways, inventory systems, loyalty programs, and security controls. Because the financial impact of a defect is direct—lost revenue, chargebacks, or brand damage—testing gift cards must go beyond superficial “happy‑path” checks. This guide walks you through a complete, repeatable process for crafting high‑signal test cases, from requirement analysis to traceability, and shows how manual design combined with autonomous exploration (e.g., using the SUSATest platform) yields real coverage. You will finish with a ready‑to‑use test matrix of 20+ examples, a short checklist, and concrete snippets for turning those cases into automated scripts.
How to Write Test Cases for Gift Cards (With Examples) – Foundations
Before you write a single test step, you must understand the domain model that underlies gift cards. Treat the gift card as a stateful entity with attributes such as cardNumber, pin, balance, currency, issueDate, expiryDate, status (inactive, active, redeemed, expired, blocked), and ), and ownerId`. Each attribute can trigger distinct business rules: a card cannot be redeemed before activation, a balance cannot go negative, an expired card must be rejected even if the cryptographic signature is valid, and a reload operation may be limited to a maximum daily amount per user.
Start by extracting these rules from product specifications, user stories, or API contracts. Write them as atomic, verifiable statements. For example:
- “When a gift card is purchased, the system must create a record with status =
inactiveand balance = purchase amount.” - “When a redeem request is submitted, the system must verify that the card status is
activeand that the requested amount ≤ current balance.”
These statements become the basis for traceability. Assign each rule a unique identifier (e.g., GC‑REQ‑001) and later map test case IDs to them. This practice prevents gaps and makes impact analysis trivial when a requirement changes.
Next, identify the actors that interact with the gift card flow: the purchaser (often a guest or registered user), the recipient (who may redeem), the merchant cashier (if a physical card is scanned), and the fraud‑prevention system (which may block anomalous patterns). For each actor, note typical behaviors and possible deviations—curious users might try to guess PINs, impatient users may refresh the page repeatedly, and adversarial users may attempt to replay old redemption requests. Capturing these personas early ensures your test cases cover both functional correctness and resilience to misuse.
Finally, decide on the test levels you will target. Unit tests can validate internal calculations (e.g., applying a promotional discount to the balance). Integration tests should verify that the gift card service correctly calls the payment gateway and updates the inventory database. End‑to‑end (e2e) tests, whether manual or automated, must exercise the full UI flow: adding a card to cart, completing checkout, receiving the card code via email or SMS, and redeeming it in the storefront or POS. By layering your test cases across these levels, you achieve both speed (fast unit feedback) and confidence (real‑world validation).
How to Write Test Cases for Gift Cards (With Examples) – Designing the Test Matrix
A well‑structured test case consists of five essential parts:
- ID – a short, unique reference (e.g.,
GC‑TC‑001). - Preconditions – the state the system must be in before execution (e.g., “a valid gift card with $50 balance exists in the database”).
- Steps – an ordered list of actions the tester or automation will perform.
- Expected Result – the observable outcome that determines pass/fail (e.g., “the redemption confirmation page shows a new balance of $0”).
- Post‑conditions (optional) – any cleanup or state verification needed for the next test (e.g., “the card record is marked as redeemed”).
Keep each step atomic and UI‑agnostic when possible; this makes the case reusable across manual, scripted, and autonomous test approaches. Avoid bundling multiple verifications into a single step—if you need to check both balance and status, split them into separate expected results.
Positive Test Cases
Positive cases validate that the system behaves correctly when all inputs are valid and the user follows the intended path. Below is a representative subset; the full matrix later expands to 20+ rows.
| TC‑ID | Preconditions | Steps | Expected Result |
|---|---|---|---|
| GC‑TC‑001 | No gift card exists for user alice@example.com. | 1. Log in as Alice. 2. Navigate to “Buy Gift Card”. 3. Choose $25 denomination. 4. Complete payment with Visa card ending in 4242. | System creates a gift card record: status=active, balance=$25, cardNumber generated, email sent with code. |
| GC‑TC‑002 | Gift card GC123456 with $100 balance, status=active. | 1. Log in as Bob (recipient). 2. Go to “Redeem Gift Card”. 3. Enter cardNumber GC123456 and PIN (if required). 4. Enter redemption amount $30. 5. Submit. | New balance = $70, status remains active. Confirmation screen shows updated balance and transaction ID. |
| GC‑TC‑003 | Gift card GC999 with $0 balance, status=active. | 1. Log in as merchant cashier. 2. Select “Reload Gift Card”. 3. Scan card GC999. 4. Enter reload amount $50. 5. Confirm with manager PIN. | Balance updated to $50, status=active. Reload transaction logged with timestamp and operator ID. |
| GC‑TC‑004 | Gift card GC555 with $20 balance, status=active. | 1. Log in as Charlie. 2. Choose “Transfer Gift Card”. 3. Enter recipient email dave@example.com. 4. Enter amount $15. 5. Submit. | Sender balance = $5, status=active. New gift card created for Dave with balance=$15, status=active. Both parties receive notification emails. |
| GC‑TC‑005 | Gift card GC777 with $10 balance, status=active. | 1. Open the gift card details page via deep link myapp://giftcard/GC777. 2. View details. | Page displays cardNumber (masked), balance=$10, expiry date, and status=active. No edit controls are shown. |
These cases cover creation, redemption, reload, transfer, and inquiry—core paths that any gift card implementation must support.
Negative and Boundary Test Cases
Negative cases verify that the system correctly rejects invalid inputs or illegal state transitions. Boundary cases push numeric limits (e.g., maximum balance, minimum reload) and date limits (expiry). Include also security‑oriented checks such as PIN brute‑force protection and replay attack detection.
| TC‑ID | Preconditions | Steps | Expected Result |
|---|---|---|---|
| GC‑TC‑006 | Gift card GC111 with $5 balance, status=active. | 1. Attempt to redeem $10 (exceeds balance). 2. Submit. | Error message: “Insufficient balance”. Balance unchanged, status=active. |
| GC‑TC‑007 | Gift card GC222 with $0 balance, status=inactive. | 1. Attempt to redeem any amount. 2. Submit. | Error: “Card not active”. No state change. |
| GC‑TC‑008 | Gift card GC333 with $100 balance, status=active. | 1. Attempt to reload with amount $0 (or negative). 2. Submit. | Validation error: “Reload amount must be greater than zero”. Balance unchanged. |
| GC‑TC‑009 | Gift card GC444 with $500 balance, status=active. | 1. Attempt to reload with amount $600 (exceeds daily limit $500). 2. Submit. | Error: “Daily reload limit exceeded”. Balance unchanged. |
| GC‑TC‑010 | Gift card GC555 with $50 balance, status=active. | 1. Attempt to transfer $51 (exceeds balance). 2. Submit. | Error: “Transfer amount exceeds available balance”. No transfer created. |
| GC‑TC‑011 | Gift card GC666 with expiry date 2023-01-01. | 1. Set system date to 2023-02-01 (past expiry). 2. Attempt redemption of $10. | Error: “Gift card has expired”. No balance change. |
| GC‑TC‑012 | Gift card GC777 with $20 balance, status=active. | 1. Rapidly submit 10 redemption requests for $1 each within 1 second. | After first successful redemption, subsequent requests return error: “Too many requests – try later” or are throttled. |
| GC‑TC‑013 | No gift card exists. | 1. Attempt to redeem with a randomly generated 16‑digit number. | Error: “Invalid gift card number”. System logs failed attempt for fraud monitoring. |
| GC‑TC‑014 | Gift card GC888 with $100 balance, status=active. | 1. Attempt to redeem using correct cardNumber but wrong PIN (if PIN required). 2. Repeat 3 times. | After 3rd failed PIN, account/card is temporarily locked (e.g., 15‑minute lockout). |
| GC‑TC‑015 | Gift card GC999 with $0 balance, status=active. | 1. Attempt to reload with amount $0.01 (sub‑cent precision not supported). | Error: “Amount must be in whole currency units”. Balance unchanged. |
These cases ensure the system guards against over‑spending, state misuse, expired cards, rate‑abuse, and malformed data—common sources of production incidents.
Edge Cases Specific to Multi‑Currency and Promotions
If your platform supports multiple currencies or promotional bonuses, add cases that verify conversion rates, bonus application, and expiry of promotional funds.
| TC‑ID | Preconditions | Steps | Expected Result |
|---|---|---|---|
| GC‑TC‑016 | User purchases a €20 gift card while account currency is USD. Exchange rate 1 EUR = 1.10 USD. | 1. Complete purchase. 2. Check gift card details. | Balance stored as $22 (rounded per policy). Currency field shows EUR, but internal USD equivalent used for calculations. |
| GC‑TC‑017 | Promotional rule: “Buy $50 gift card, get $5 bonus”. | 1. Purchase $50 gift card. 2. Verify bonus applied. | Primary balance = $50, bonus balance = $5. Total redeemable amount = $55. |
| GC‑TC‑018 | Bonus balance expires after 30 days; primary balance does not. | 1. Wait 31 days (or adjust system clock). 2. Attempt to redeem $5 bonus. | Error: “Promotional balance expired”. Primary $50 still redeemable. |
| GC‑TC‑019 | User attempts to redeem a gift card with mixed currency (e.g., card issued in GBP, storefront expects USD). | 1. Choose product priced in USD. 2. Attempt to pay with GBP gift card. | System either auto‑converts using current rate and shows converted amount, or rejects with “Currency mismatch”. |
| GC‑TC‑020 | Gift card with maximum allowed balance (e.g., $5,000). | 1. Reload $4,900 onto card with $100 existing balance. 2. Attempt to reload another $200. | First reload succeeds, balance = $5,000. Second reload rejected: “Maximum balance exceeded”. |
These examples illustrate how to extend the matrix to cover domain‑specific nuances that often slip through generic test suites.
Test Case Anatomy – Writing Clear, Maintainable Steps
A test case is only as good as its readability. Use imperative mood, keep each step to a single action, and avoid implementation details that may change (e.g., “click the button with id redeemBtn” is acceptable if the ID is stable; otherwise refer to the button by its label). When a step involves data entry, specify the exact value or a variable placeholder (e.g., “Enter cardNumber = {{CARD_NUM}}”). This makes the case amenable to data‑driven execution.
Include a short rationale in a comment block if the intent is not obvious from the steps. For example:
# Purpose: Verify that the system prevents redemption of an inactive card.
# References: GC‑REQ‑004, GC‑REQ‑009
When you anticipate that a step might be reused across multiple cases (e.g., “Log in as a registered user”), extract it into a shared precondition or a helper keyword in your test automation framework. This reduces duplication and simplifies updates when the login flow changes.
Data Setup and Test Data Management
Reliable gift card tests depend on predictable data. Adopt one of three strategies:
- Database seeding – before each test run, insert known gift card records directly into the test database using SQL or an ORM script. This is fast and gives you full control over fields like
cardNumberandpin. - API‑based provisioning – call the internal “create gift card” endpoint with admin credentials to generate cards on the fly. This mimics the real purchase flow but requires the endpoint to be accessible in the test environment.
- UI‑driven creation – use the actual purchase flow to generate cards, then immediately use them in subsequent steps. This is the most realistic but also the slowest; reserve it for end‑to‑end validation.
Whichever method you choose, always clean up after the test (delete the card, reset balances, or mark it as inactive) to avoid cross‑test contamination. If your test environment supports snapshots or container recreation, leverage those for a clean slate between suites.
For data‑driven testing, store test data in CSV or JSON files with columns matching the placeholders in your test steps (e.g., cardNumber, pin, amount, expectedBalance). Most test runners (TestNG, JUnit, pytest, Playwright test) can iterate over these files automatically.
Prioritization and Traceability
Not all test cases carry equal risk. Apply a simple risk‑based scoring model:
- Impact – financial loss if the defect reaches production (high for balance manipulation, low for UI label typo).
- Likelihood – how easily the defect can be triggered (high for boundary inputs, low for exotic edge cases).
Compute a priority score = Impact × Likelihood (both on a 1‑5 scale). Cases scoring ≥12 become P1 (must run on every build), 8‑11 become P2 (run nightly), and ≤7 become P3 (run weekly or before release).
Maintain a traceability matrix linking each test case ID to the requirement IDs it validates. A simple two‑column table works:
| Test Case ID | Requirement IDs Covered |
|---|---|
| GC‑TC‑001 | GC‑REQ‑001, GC‑REQ‑002 |
| GC‑TC‑006 | GC‑REQ‑004, GC‑REQ‑007 |
| GC‑TC‑012 | GC‑REQ‑009, GC‑REQ‑010 |
| … | … |
When a requirement changes, you can instantly identify affected test cases and update or retire them. This traceability also satisfies audit needs for regulated industries (e.g., gift cards subject to escheatment laws).
Manual Execution Best Practices
Even when you plan to automate, manual exploratory testing remains valuable for discovering usability issues and unexpected interactions. Follow these practices:
- Session‑based test management – allocate 45‑minute sessions with a clear charter (e.g., “Test gift card reload flow under poor network conditions”).
- Use personas – adopt the curious, impatient, adversarial, elderly, and accessibility profiles defined by SUSATest or similar frameworks. For each persona, adjust your pacing, input methods, and error‑tolerance.
- Leverage tools – employ a network throttling tool (e.g., Chrome DevTools,
tcon Linux) to simulate 3G or packet loss; use a screen‑reader (VoiceOver, TalkBack) to verify WCAG compliance; use a virtual smart card reader if testing physical card scans. - Document observations – capture screenshots, logs, and timestamps for any anomaly. If you encounter a crash, note the device OS version, app version, and steps to reproduce.
- Iterate – after a session, debrief with the developer or product owner to confirm whether the observed behavior is a bug, a feature, or a misunderstanding.
Manual testing shines when validating the look and feel of gift card emails, the accessibility of the redemption modal, or the clarity of error messages—areas where automated scripts may miss nuance.
Automated Script Generation from Test Cases
Once your test cases are written, convert them into automated scripts. The process can be fully manual, semi‑automatic (using a test case management tool that exports to code), or fully automatic (using a DSL or model‑based approach). Below are concrete examples for two popular stacks: Appium for Android native apps and Playwright for web applications.
Appium (Java) Example – Redeem Gift Card
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.*;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class GiftCardRedeemTest {
private AppiumDriver<MobileElement> driver;
@BeforeClass
public void setUp() throws Exception {
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("deviceName", "Pixel_4_API_30");
caps.setCapability("platformName", "Android");
caps.setCapability("appPackage", "com.example.shop");
caps.setCapability("appActivity", ".MainActivity");
caps.setCapability("automationName", "UiAutomator2");
driver = new AndroidDriver<>(new URL("http://localhost:4723/wd/hub"), caps);
}
@Test(dataProvider = "redeemData")
public void testRedeem(String cardNumber, String pin, String amount, String expectedBalance) {
// Precondition: ensure card exists with known balance (setup via API)
// 1. Navigate to gift card screen
driver.findElement(By.id("nav_giftcard")).click();
// 2. Choose Redeem
driver.findElement(By.id("btn_redeem")).click();
// 3. Enter card number
driver.findElement(By.id("input_card_number")).sendKeys(cardNumber);
// 4. Enter PIN if required
if (!pin.isEmpty()) {
driver.findElement(By.id("input_pin")).sendKeys(pin);
}
// 5. Enter amount
driver.findElement(By.id("input_amount")).sendKeys(amount);
// 6. Submit
driver.findElement(By.id("btn_submit")).click();
// 7. Verify balance
MobileElement balanceEl = driver.findElement(By.id("txt_balance"));
String actual = balanceEl.getText().replace("$", "").trim();
assert actual.equals(expectedBalance) :
"Balance mismatch: expected " + expectedBalance + ", got " + actual;
}
@DataProvider
public Object[][] redeemData() {
return new Object[][]{
{"GC123456", "1234", "30", "70"},
{"GC999999", "", "0", "100"} // insufficient funds case
};
}
@AfterClass
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
Key points:
- The test is data‑driven; you can feed the CSV from the earlier test matrix.
- Preconditions (card creation) are handled via a separate API setup method or a
@BeforeMethodthat calls a backend service. - Assertions focus on observable outcomes (balance text) rather than internal states.
Playwright (TypeScript) Example – Purchase Gift Card
import { test, expect } from '@playwright/test';
test.describe('Gift Card Purchase Flow', () => {
test('user can buy a $25 gift card and receives email code', async ({ page }) => {
// Precondition: logged in as test user
await page.goto('https://shop.example.com/login');
await page.fill('#email', 'testuser@example.com');
await page.fill('#password', 'SecurePass!123');
await page.click('button[type=submit]');
await expect(page).toHaveURL(/.*\/dashboard/);
// Steps
await page.click('text=Buy Gift Card');
await page.selectOption('#denomination', '25'); // assumes dropdown value
await page.fill('#cardMessage', 'Happy Birthday!');
await page.click('button#checkout');
// Payment mock – replace with your test payment gateway
await page.fill('#cardNumber', '4242424242424242');
await page.fill('#expiry', '12/30');
await page.fill('#cvc', '123');
await page.click('button#pay');
// Confirmation
await expect(page.locator('text=Gift card purchased')).toBeVisible();
const codeLocator = page.locator('#giftCardCode');
await expect(codeLocator).toBeVisible();
const code = await codeLocator.textValue();
expect(code.length).toBeGreaterThanOrEqual(12); // basic format check
// Optional: verify email via a test mailbox (e.g., MailSlurp)
// ...
});
});
This script demonstrates:
- Clear separation of navigation, action, and verification.
- Use of Playwright’s auto‑waiting and assertions.
- Placeholder for email verification, which you can implement with a test mailbox service.
Generating Scripts from the Matrix Automatically
If you prefer a low‑code approach, export your test case table to CSV and use a simple Jinja2 template to produce Appium or Playwright snippets. Example pseudo‑code:
import csv, jinja2, os
template = jinja2.Template(open('appium_test.j2').read())
with open('giftcard_cases.csv') as f:
reader = csv.DictReader(f)
for row in reader:
rendered = template.render(
tc_id=row['ID'],
steps=row['Steps'].split(' | '),
expected=row['ExpectedResult']
)
os.makedirs('generated', exist_ok=True)
with open(f'generated/{row["ID"]}.java', 'w') as out:
out.write(rendered)
The Jinja2 template (appium_test.j2) would contain the boilerplate test class with placeholders for each step. This approach guarantees that any change to the matrix propagates instantly to the automation suite.
Integrating Autonomous Exploration (SUSA)
Manual and scripted tests cover the paths you anticipate, but real users often behave in ways that no tester imagines. Autonomous exploration tools like SUSATest can supplement your suite by exercising the app without predefined scripts, discovering crashes, ANRs, dead buttons, accessibility violations, and UX friction.
How SUSA Works in Brief
After you install the agent (pip install susatest-agent), you point it at either an APK file or a web URL. The agent launches the app and then drives it using a combination of model‑based exploration and learned heuristics. It simulates eight distinct personas—curious, impatient, novice, adversarial, elderly, accessibility‑focused, power user, and a default “explorer”—each with its own probability distribution for actions such as long presses, rapid taps, voice input, or navigating via screen readers. As it runs, SUSA builds a graph of visited screens, marks dead ends, and remembers which inputs caused exceptions. Subsequent runs start from this knowledge base, making the exploration smarter over time.
Practical Steps to Run SUSA on a Gift Card Flow
- Prepare the environment – Ensure your test backend is reachable (e.g., a staging server with a resetable database).
- Launch the agent – For an Android app:
susatest run --apk path/to/app.apk \
--device emulator-5554 \
--duration 30m \
--personas all \
--output ./susa-report
For a web storefront:
susatest run --url https://staging.shop.example.com \
--browser chrome \
--duration 20m \
--personas curious,adversarial,accessibility \
--output ./susa-report
- Analyze the report – The output includes a JSON file listing every discovered screen, a list of failed actions (e.g., “Button ‘Redeem’ threw NullPointerException”), and a heatmap of screens visited most often. Look for:
- Any screen where the balance field is missing or incorrectly formatted.
- Dialogs that appear after a rapid succession of taps (possible race condition).
- Accessibility violations such as missing
contentDescriptionon the gift card image. - Unexpected navigation to a login screen after a reload operation (indicating a session drop).
- Feed findings back into your test matrix – Each defect uncovered by SUSA should become a new test case (or a refinement of an existing one). For example, if SUSA finds that entering a negative amount in the reload field triggers a crash, add a boundary case like GC‑TC‑008‑B: “Attempt to reload with –$10; expect validation error, not crash.”
- Schedule regular runs – Integrate the
susatestcommand into your CI pipeline as a nightly job. Because the agent retains its explored state, each nightly run will cover new ground while quickly re‑checking previously seen paths.
Benefits of Combining Designed Cases with Autonomous Exploration
- Coverage completeness – Designed test cases guarantee that all specified requirements are exercised. Autonomous exploration fills the gaps left by undocumented or implicit requirements (e.g., error handling for malformed deep links).
- Early detection of flaky behavior – SUSA’s varied timing and persona‑driven inputs often surface race conditions that only appear under specific load or device states, which deterministic scripts might miss.
- Reduced maintenance overhead – When the UI changes, SUSA will automatically adapt its exploration model (it does not rely on hard‑coded locators). Your scripted suite may need locator updates, but the exploratory runs continue to provide value.
- Rich persona data – The reports include metrics per persona (e.g., “elderly persona took 3.2× longer to complete redemption”), which can inform UX improvements directly tied to accessibility goals.
Checklist for Gift Card Test Suite Health
Use this short checklist before each release to verify that your gift card testing is in good shape.
- [ ] All requirement IDs (
GC‑REQ‑xxx) have at least one linked test case ID. - [ ] Positive paths cover purchase, redemption, reload, transfer, and inquiry for each supported currency and promotional rule.
- [ ] Negative and boundary cases include: insufficient balance, inactive/expired card, zero or negative amounts, daily/monthly limits, PIN attempt throttling, and malformed card numbers.
- [ ] Data‑setup scripts are idempotent and clean up after each test (or use transaction rollback).
- [ ] At least 80 % of test cases are automated (Appium, Playwright, or unit/service level).
- [ ] Manual exploratory sessions have been run with each of the eight SUSA personas in the last week.
- [ ] CI pipeline executes the full automated suite on every pull request and runs the SUSA agent nightly.
- [ ] Test reports are archived and linked to the corresponding build or release artifact.
- [ ] Any defect found by SUSA or manual testing has been converted into a test case and added to the regression suite.
- [ ] Test case documentation includes a short rationale and references to the requirement IDs.
Final Takeaways
Writing effective test cases for gift cards is not a matter of checking a box that says “the card works.” It requires a deep dive into the financial flows, state transitions, security guards, and user‑behavior variations that surround a seemingly simple piece of code or UI. By starting with clear, traceable requirements, constructing a balanced matrix of positive, negative, boundary, and edge cases, and then executing those cases through a mix of manual, automated, and autonomous techniques, you achieve both verification of spec compliance and discovery of the hidden defects that erode trust and revenue.
Remember to treat test data as a first‑class citizen—seed it, clean it, and version it alongside your test scripts. Keep your test cases atomic, data‑driven, and loosely coupled to UI identifiers so they survive redesigns. Leverage tools like SUSATest to continuously explore the unknown, and feed any new findings back into your test base as immediate regression guards.
When you follow the process outlined here, you’ll have a living test suite that not only passes today’s build but evolves with your application, protects revenue, and delivers a reliable gift‑card experience for every kind of user. Happy testing.
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free