Test-design coverage matrix (equivalence & boundary)
Builds on Topic 7.
What you'll produce
A test-design coverage matrix that applies equivalence partitioning and boundary value analysis to the two riskiest fields in the ShopSphere checkout — the promo-code field and the quantity / order-amount fields — plus a short exploratory-testing charter. For each field you list the equivalence classes (the groups the system should treat the same), pick one representative value per class, then add the boundary values right at and around each edge — turning what could be hundreds of brute-force inputs into a tight, defensible set. This proves the Topic 7 skill that separates a junior who "clicks around" from a tester a lead trusts: covering more with fewer, well-chosen test cases, and being able to justify exactly why each one earns its place. It also makes you faster every release — a small, technique-driven set runs in minutes and still catches the off-by-one and class-handling bugs that hide in checkout math.
Instructions
- Pick the fields to analyze. From your Deliverable-2 suite, choose the inputs where wrong handling costs the most. For ShopSphere that's the promo-code field (string with format + state rules) and the quantity and order-amount/free-shipping-threshold numbers. Note the rule for each from the spec (allowed length, allowed characters, valid range, the magic numbers like minimum order or free-shipping threshold).
- Partition into equivalence classes. For each field, list every class the system should treat the same — and split valid classes from invalid classes. A promo code, for example, is not one "invalid" bucket: wrong format, well-formed but unknown, expired, and already-used are different classes the code path handles differently. Capturing those distinct invalid classes is where most of the value is.
- Choose one representative value per class. Write a real, concrete value (
SAVE20,41,$34.99) — never "a valid code." One value stands in for its whole class; that's the partitioning payoff. - Add boundary values around every numeric edge. For each range or threshold, test at the boundary, one below, and one above (the min, min−1, min+1 pattern). Cover the field's own limits (quantity 1, max-per-order) and the business thresholds buried in the logic (free-shipping at $35 → test $34.99, $35.00, $35.01; promo minimum at $20 → test $19.99, $20.00). Edges are where off-by-one bugs cluster.
- Build the matrix. One row per test idea, columns: Field · Class (valid/invalid) · Technique (EP / BVA) · Input value · Expected result. Keep expected results specific ("Order total recalculates to $67.49; 10% discount line shows −$7.50"), not "works."
- Trace to your suite and prune. Tag each row with the test-case ID it maps to (or "NEW" / "gap"). Where two rows would exercise the identical code path, keep one and say so — demonstrating you cut redundancy on purpose, not by accident.
- Write the exploratory-testing charter. Techniques only cover what you anticipated. Add a 3–4 line charter in the standard form — Explore [area] with [resource/technique] to discover [information] — plus a timebox and 4–6 "what if I…?" hunches the matrix can't script (paste an emoji code, apply a code then change quantity, hit Back mid-apply).
Worked example
(Feature: ShopSphere checkout — promo-code field and quantity/amount. All rules and codes are the shared Capstone fixtures, so the boundaries trace to one set of real rules: promo codes are 4–10 chars, uppercase letters + digits only; valid quantity per line item is 1–10; free shipping unlocks at a $35.00 subtotal; the active promo SAVE20 gives 20% off with a $20.00 minimum cart. WELCOME15, SUMMER19 (expired), and SUMMER20 (case-insensitive alias of SAVE20) carry the same effects/rules as in Deliverable 2.)
Field A — Promo-code field
| # | Class (valid / invalid) | Technique | Input value | Expected result |
|---|---|---|---|---|
| A1 | Valid, active code, order ≥ minimum | EP | SAVE20 (subtotal $80.00) | Accepted; −$16.00 discount line; total $64.00; "Promo code applied" confirmation |
| A2 | Valid format, below min-cart rule | EP (boundary of $20.00 rule) | SAVE20 (subtotal $19.99) | Rejected: "Add $0.01 more to use this code (minimum $20.00)"; no discount applied |
| A3 | Well-formed but unknown code | EP (invalid class) | FAKE99 | Rejected: "Invalid promo code"; total unchanged; field stays editable |
| A4 | Expired code | EP (invalid class) | SUMMER19 (expired 2026-05-31) | Rejected: "This code has expired"; total unchanged |
| A5 | Already-redeemed single-use code | EP (invalid class) | WELCOME15 (already redeemed on this account) | Rejected: "This code has already been used"; total unchanged |
| A6 | Wrong format — lowercase / symbols | EP (invalid class) | save-20 | Rejected at validation: "Letters and numbers only"; not sent to server |
| A7 | Below min length boundary (3 chars) | BVA (min−1) | AB1 | Rejected: too short; Apply stays disabled |
| A8 | At min length boundary (4 chars) | BVA (min) | SAVE (4-char length probe — passes the format gate) | Passes client-side length/format validation; sent to the server for catalog lookup |
| A9 | At max length boundary (10 chars) | BVA (max) | WELCOME15X (10-char length probe — passes the format gate) | Passes client-side length/format validation; sent to the server for catalog lookup |
| A10 | Above max length boundary (11 chars) | BVA (max+1) | WELCOME15XY | 11th char blocked or trimmed; never accepted as valid |
| A11 | Empty field, Apply tapped | EP (invalid/empty class) | `` (blank) | Graceful message "Enter a code"; no crash — guards the known empty-field defect |
Field B — Quantity & order-amount
| # | Class (valid / invalid) | Technique | Input value | Expected result |
|---|---|---|---|---|
| B1 | Valid in-range quantity | EP | 4 | Line item shows qty 4; subtotal = unit price × 4 |
| B2 | Below min quantity boundary | BVA (min−1 = 0) | 0 | Treated as remove, or rejected — never a $0/empty line that still checks out |
| B3 | At min quantity boundary | BVA (min = 1) | 1 | Accepted; standard single-unit line |
| B4 | At max quantity boundary | BVA (max = 10) | 10 | Accepted; subtotal correct at the cap |
| B5 | Above max quantity boundary | BVA (max+1 = 11) | 11 | Blocked: "Max 10 per item"; quantity held at 10 |
| B6 | Non-numeric / invalid quantity | EP (invalid class) | abc / -2 | Rejected; quantity unchanged; no negative line total |
| B7 | Subtotal just below free-ship threshold | BVA (threshold−$0.01) | subtotal $34.99 | Shipping charged ($5.99); "Add $0.01 for free shipping" nudge shown |
| B8 | Subtotal exactly at threshold | BVA (threshold = $35.00) | subtotal $35.00 | Free shipping applied; shipping line $0.00 |
| B9 | Subtotal just above threshold | BVA (threshold+$0.01) | subtotal $35.01 | Free shipping applied; shipping line $0.00 |
| B10 | Promo pushes order below threshold | EP × interaction | SAVE20 on $38.00 → $30.40 | Spec-decision check: does free shipping recompute on the post-discount $30.40 (now < $35.00, so shipping reappears) or hold on the pre-discount $38.00? Result must match spec, consistently |
Coverage logic: 21 representative inputs replace the effectively infinite input space. Field A turns "every possible string" into 11 meaningful checks across 1 valid and 6 distinct invalid classes plus 4 length boundaries; Field B pins all three numeric edges (quantity 0/1/10/11) and the money edge ($34.99 / $35.00 / $35.01) that brute-force clicking almost always misses. Trace to the Deliverable-2 suite: A1→TC-PROMO-01 (valid SAVE20), A2→TC-PROMO-07 (below-min boundary, partner of TC-PROMO-08), A3→TC-PROMO-04 (invalid code), A4→TC-PROMO-05 (expired), A5→TC-PROMO-12 (single-use reuse), A11→TC-PROMO-06 (empty submission). B7–B9 are NEW — the Deliverable-2 suite pinned the $20.00 promo-minimum boundary but had no boundary on the $35.00 free-shipping threshold, so these three rows fill a logged coverage gap. A8 and A9 exercise the same length-validation path, so a fuller deck could drop A9 if time is tight; B10 is the highest-value row because it exposes an unstated spec decision (does the free-ship recompute use the pre- or post-discount subtotal?), not just a bug.
Exploratory-testing charter
Explore the promo-code-plus-cart interaction with valid, invalid, and boundary inputs in rapid combination to discover state, recalculation, and resilience bugs the scripted matrix can't anticipate. Timebox: 45 minutes, staging build, Safari iOS + Chrome desktop, session notes captured.
Hunches to chase: (1) apply
SAVE20, then raise quantity from 4→10 — does the discount recompute or stick to the old subtotal? (2) Paste a code with a trailing space / an emoji / 200 characters. (3) Apply a valid code, hit browser Back mid-apply, then resubmit — does it double-apply or strip? (4) Apply, then remove items so the subtotal drops below the $20.00 minimum, proceed — is the now-invalid discount still honored at payment? (5) Two codes in a row — does the second replace or stack? (6) Lose network right after tapping Apply — graceful error or spinner-of-death?
Rubric
The app's AI scores the learner's submission against these criteria and gives feedback. Levels: Needs work (1) / Solid (2) / Excellent (3). Passing = every criterion at Solid or above.
- Equivalence classes — 1: lumps all invalids into one bucket or misses valid/invalid split · 2: valid and invalid classes both identified for each field · 3: distinct invalid classes broken out (unknown vs. expired vs. used vs. wrong-format) with a representative value each.
- Boundary value analysis — 1: no boundaries, or only the middle of ranges tested · 2: tests the field's own min/max edges with the at/below/above pattern · 3: also pins the business thresholds in the logic (free-shipping at $35 → $34.99 / $35.00 / $35.01; promo minimum at $20 → $19.99 / $20.00) where off-by-one bugs hide.
- Concrete, specific values & expected results — 1: placeholders like "a valid code" / "it works" · 2: real input values and checkable expected results · 3: precise inputs with exact expected math (discount amount, recomputed total, specific error text).
- Coverage efficiency & justification — 1: brute-force list or arbitrary picks · 2: one value per class, redundancy mostly avoided · 3: explicitly shows the few-tests-cover-much logic, prunes duplicate code paths on purpose, and flags the highest-value rows.
- Exploratory-testing charter — 1: missing or a vague "click around" · 2: a charter in the explore/with/to-discover form with a timebox · 3: a sharp charter plus several genuinely unscriptable "what if I…?" hunches (state, recalculation, interaction, resilience).
- Coherence with prior deliverables — 1: disconnected from the suite · 2: rows trace to test-case IDs · 3: traces cleanly to the Deliverable-2 suite, tags NEW rows, and surfaces a real coverage gap it fills.