test-case-anatomy-reference
Pure-reference catalog of test-case anatomy and review quality - what fields a well-formed test case must have, what each field means, and how to score the content once the fields are filled. Enumerates the ISO/IEC/IEEE 29119-3:2021 test-case template fields (identifier, objective, preconditions, inputs, steps, expected results, postconditions, environment, traceability) and the ISTQB CTAL-TM specification-technique-driven additions (equivalence partition, boundary value, decision table, state transition), maps the canonical anatomy to five tracker-specific schemas (TestRail, Xray, Zephyr Scale, Allure TestOps, Qase), and carries the review rubric: six per-case quality axes plus six set-level axes with PASS / WEAK / FAIL verdicts derived without averaging, each threshold marked standard-backed or practitioner convention. Use as the authoritative source when authoring a case template, reviewing a batch of test cases for quality, or migrating between tools.
Install with skills.sh (any agent)
npx skills add testland/qa --skill test-case-anatomy-referencetest-case-anatomy-reference
Overview
A test case has nine required parts. Skipping any of them produces a case that's either ambiguous (a tester can't run it) or unverifiable (a reviewer can't tell if it passed). The canonical list comes from ISO/IEC/IEEE 29119-3:2021 ยง6, augmented by ISTQB CTAL-TM's specification-based-testing additions.
This skill is a pure reference consumed by traceability-matrix-builder, tcm-case-management (and its five per-vendor references), and the test-case-quality-critic agent.
When to use
How to use
The nine canonical fields (ISO 29119-3 ยง6)
Per ISO/IEC/IEEE 29119-3:2021 "Software and systems engineering - Software testing - Part 3: Test documentation" (cite by stable ID; full text behind iso.org paywall):
| # | Field | Purpose | Common mistakes |
|---|---|---|---|
| 1 | Identifier | Unique ID for cross-reference, traceability, defect linking. | Reusing IDs after deletion; non-stable IDs across migrations. |
| 2 | Objective | One-sentence statement of what's being verified. | Vague ("test checkout"); should state behaviour ("verify discount applies before tax"). |
| 3 | Preconditions | System state required before the case runs. | Implicit ("user is logged in"); should be executable / verifiable. |
| 4 | Inputs | Specific data values fed to the system. | Generic ("a valid email"); should be concrete ("alice@example.com"). |
| 5 | Steps | Numbered actions the tester performs. | Combining actions ("login and add item"); should be one action per step. |
| 6 | Expected results | What the system should produce per step / overall. | Missing per-step results; should pair each action with its expected outcome. |
| 7 | Postconditions | System state after the case (cleanup expectations). | Omitted; matters for shared environments. |
| 8 | Environment | Where the case is valid (browser, OS, build, locale). | Universal-applicability assumption; should constrain explicitly. |
| 9 | Traceability | Links to requirements, designs, defects. | One-way link only (case โ req); should be bidirectional. |
ISTQB CTAL-TM specification-technique additions
Per the ISTQB Advanced Test Manager and Test Analyst syllabi, when a case is derived from a specification technique, it carries technique-specific metadata:
| Technique | Additional fields |
|---|---|
| Equivalence partitioning | Partition (valid/invalid), partition label, representative input |
| Boundary value analysis | Boundary (min, max, on/off), the specific BVA value (-1, 0, 1, 99, 100, 101) |
| Decision table | Rule ID, condition vector, action vector |
| State transition | Starting state, event, ending state, output |
| Use case | Main success scenario step, extension point |
| Classification tree | Tree node path |
These fields don't replace the nine above - they're traceability to the design technique that produced the case. Per the ISTQB glossary (glossary.istqb.org (opens in new window)).
Tracker-schema map
Five common trackers (TestRail, Xray, Zephyr Scale, Allure TestOps, Qase) each store the canonical anatomy under different field names, plus their own severity / priority / type enums. The full per-tracker field map and the cross-platform severity / priority / type table live in references/tracker-schema-map.md. Consult it when migrating cases between tools or writing to a specific tracker's fields.
Field cardinality reference
A migration / template author must know which fields are one-to-one and which are one-to-many:
| Field | Cardinality |
|---|---|
| Identifier | 1 |
| Objective | 1 |
| Preconditions | 1 (free text) or n (linked sub-entities, Xray-style) |
| Steps | n (ordered) |
| Inputs | n (per step) |
| Expected results | n (one per step + optional overall) |
| Postconditions | 1 |
| Environment | n (browser ร OS ร locale ร build) |
| Traceability | n (requirements, designs, defects) |
| Severity | 1 |
| Priority | 1 |
| Type | 1 |
| Automation status | 1 |
| Tags | n |
Review rubric
The anatomy above answers "which fields"; this rubric answers "is the content in them any good" - given a case whose fields are already populated, is the content good enough to hand to someone else? Anchor definition: a test case is "a set of preconditions, inputs, actions (where applicable), expected results and postconditions, developed based on test conditions" (ISTQB glossary, test case, V4.7.2 (opens in new window)). Every axis tests one clause of that sentence.
Gate 0: is the case scorable at all?
Run this before scoring. A case that fails Gate 0 gets no axis verdicts: it is reported as UNSCORABLE with the missing field named, and returned to its author. Separating presence from quality keeps a templated stub from being reported as six independent quality defects.
| Gate 0 check | Result if absent |
|---|---|
| Identifier present and unique | UNSCORABLE |
| Objective (title) present | UNSCORABLE |
| Preconditions present | UNSCORABLE |
| At least one step present | UNSCORABLE |
| At least one expected result present | UNSCORABLE |
| Environment stated | Score normally, raise a warning |
| Priority, severity, type populated | Score normally, raise a warning |
| Traceability reference present | Score normally, scored by axis A6 |
Per-case axes
| ID | Axis | PASS bar | FAIL trigger | Basis |
|---|---|---|---|---|
| A1 | Objective specificity | The title names a concrete observable behavior and a single verification. "Applies a 10 percent coupon to the subtotal before tax". | Title names only the feature or the activity: "Test checkout", "Checkout works", "Login". Or it joins two unrelated verifications with and. | ISO/IEC/IEEE 29119-3:2021 objective field; specificity bar is convention. |
| A2 | Precondition executability | Each precondition names a state a second tester can reach and confirm: named account, named fixture, named build, named data row. | Precondition is a mood rather than a state: "system is ready", "user has data". Or it is stated but not reachable ("prod DB in Tuesday's shape"). | ISTQB precondition: "the required state of a test item and its test environment prior to test execution" (glossary (opens in new window)). |
| A3 | Step granularity | Each step is one interaction and carries its own expected result. | A step combines two interactions ("log in and add to cart"), or a step has no paired expected result, or the step's leading verb is Test / Verify / Check instead of naming an interaction. | ISTQB test step: "a single interaction between an actor and a test object consisting of an input, an action, and an expected result" (glossary (opens in new window)). |
| A4 | Step abstraction match | Step phrasing sits at the layer the objective claims to verify. | A business-rule case is written in DOM mechanics (click #btn-checkout-submit), or a UI-mechanics case is written so abstractly the mechanic under test disappears. | Convention, informed by Cucumber, Writing better Gherkin (opens in new window): declarative phrasing "helps you focus on the value that the customer is getting, rather than the keystrokes they will use". |
| A5 | Expected-result observability | Every expected result names something a tester can observe and compare without judgment: a value, a state, a message, a status code. | Expected result asserts a quality rather than an observation: "works correctly", "performs well", "looks right". Or it needs a judgment call with no documented bar. | ISTQB expected result: "the observable predicted behavior of a test item under specified conditions based on its test basis" (glossary (opens in new window)). Where a bar is needed, name the oracle (glossary (opens in new window)). |
| A6 | Traceability validity | The reference resolves to a live requirement, acceptance criterion, or a named exploratory charter. | The reference is present but stale: it points at a requirement that no longer exists. A stale reference is worse than none, because it reports coverage that does not exist. | ISTQB traceability (glossary (opens in new window)); ISTQB CTFL v4.0 section 1.4.4: "traceability of test cases to requirements can verify that the requirements are covered by test cases" (syllabus PDF (opens in new window)). |
A6 note on the empty case: a missing reference is WEAK, not FAIL. A case with no link is still runnable; a case with a wrong link actively misreports coverage. An intentionally unlinked case (an exploratory charter, a smoke check covering no single requirement) passes A6 when the absence is stated in the case rather than left blank.
Set-level axes
Run these once over the whole set, never per case. They diagnose the shape of the suite, not the craft of any one case.
| ID | Axis | PASS bar | FAIL trigger | Basis |
|---|---|---|---|---|
| S1 | Equivalence-partition coverage | For every parameter the set exercises, each identified partition (valid and invalid) is covered by at least one case. | Only valid partitions covered, or several cases pile into one partition while others are untouched. | ISTQB CTFL v4.0 section 4.2.1: "test cases must exercise all identified partitions (including invalid partitions) by covering each partition at least once" (syllabus PDF (opens in new window)). |
| S2 | Boundary coverage | For every ordered partition with a declared bound, the boundary values are exercised. State which BVA variant the set claims: 2-value covers each boundary and its closest neighbor in the adjacent partition; 3-value covers the boundary and both neighbors. | Bounded parameters have cases only at partition midpoints. | ISTQB CTFL v4.0 section 4.2.2, which defines both 2-value and 3-value BVA and their coverage items (syllabus PDF (opens in new window)). |
| S3 | Duplication | No two cases assert the same postcondition under the same precondition with only cosmetic variation. | Near-identical cases that differ only in title wording or in an input value inside the same partition. | Follows from S1: two cases in one partition are one coverage item. |
| S4 | Orphans and uncovered requirements | Every requirement in scope has at least one case; every case either links to a requirement or declares why it does not. | Requirements in scope with zero linked cases. Report both directions. | ISTQB CTFL v4.0 section 1.4.4: "accurate traceability supports coverage evaluation". |
| S5 | Tier shape | The set has a defensible mix of smoke, regression, negative, and edge cases, matching what the team says the suite is for. | All-smoke sets, or zero negative cases in a set that covers a validated input. | Convention, not a standard. See "Conventions" below. |
| S6 | Identifier consistency | One identifier scheme across the set. | CART-142-TC-01 mixed with cart-tc-2 mixed with Test Case 03. Inconsistent IDs break defect links and coverage rollups. | Convention. |
Scoring and verdict derivation
Per case, take the worst axis verdict: any axis FAIL = FAIL (not runnable by a second person as written; rewrite before execution); no FAIL but one or more WEAK = WEAK (runnable, fix within the sprint); all PASS = PASS.
Per set: any case FAIL / UNSCORABLE or any set axis FAIL = BLOCK; no FAIL anywhere but one or more WEAK = PASS WITH CAVEATS; else PASS.
Two rules keep the aggregate honest: never average (a percentage hides which cases are broken), and never let the aggregate replace the detail (BLOCK on a 200-case set with three failing cases means "fix these three", named by identifier - not "the suite is bad").
Conventions, stated plainly
Three thresholds in common use have no standard behind them. They are tripwires that start a conversation, not pass / fail lines; a team with calibrated numbers should use those instead.
| Convention | Common value | What it is really detecting |
|---|---|---|
| Step-count ceiling | Roughly 15 steps | Not length: a long case is usually a case with more than one objective. Check A1 first; if the title still names a single behavior, a 20-step case may be correct. Flag as WEAK, never FAIL. |
| Tier distribution bands | Smoke 10-20%, regression 50-70%, negative 15-25%, edge 5-15% | Whether anyone designed the suite. The failure the bands catch is the all-smoke or zero-negative set, not a set five points outside a band. |
| Unresolved-provenance threshold | More than 30% of cases with blank or placeholder references | An upstream authoring problem, not a case-review problem. Above the line, stop reviewing and fix how cases are written. |
Nothing in the ISTQB glossary, the CTFL v4.0 syllabus, or ISO/IEC/IEEE 29119-3:2021 sets these numbers; presenting them as standards is the most common way a review loses the author's trust.
Judgment calls reviewers split on
A weak case scored FAIL across the axes, then its PASS rewrite with per-axis before / after evidence, is worked end to end in references/review-rubric-worked-examples.md.
Rubric limitations
Anti-patterns
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| One step per case | Cases proliferate; coverage harder to track | Group related steps into one case with multiple ordered steps |
| Steps as a single text blob | Per-step pass/fail tracking impossible | Use Steps template (TestRail) / steps array (everywhere else) |
| Implicit preconditions | "User is logged in" - but as whom? | State preconditions in verifiable terms |
| Generic inputs | "Use a valid email" - tester picks one, results vary | Specify concrete inputs |
| No traceability links | Case-to-requirement orphans; coverage reporting broken | Always link to at least one requirement |
| Missing expected results per step | Tester runs steps but can't tell what to assert | Pair every step with its expected outcome |
| Tracker-specific case structure mixed in | Migration cost exploded | Author cases in the canonical anatomy; let tracker mapping be additive |
| Reusing IDs after deletion | History broken; defect links point to ghost cases | IDs are immutable; deletion is soft |
| Scoring a stub with empty fields across all six axes | Six findings for one problem; buries the real signal | Gate 0 first: report UNSCORABLE with the missing field named |
| Reporting a single percentage for a reviewed set | Hides which cases are broken; nothing gets fixed | Per-case verdicts, then a routing verdict derived from them |
| Quoting the step ceiling or tier bands as standards | Conventions with no standard behind them; overstating them costs trust on the standard-backed axes | Say "our convention" and give the reason |
| Rewriting cases silently during review | The author loses the context; the same defect returns next batch | Score, cite the axis, propose the rewrite; leave the commit to the author |
Worked example
A reviewer receives a draft case titled "test checkout" with a single free-text blob: "log in, add item, apply code SAVE10, pay, order confirmed." Walking it against the nine canonical fields:
Mapping to TestRail via the tracker-schema map: objective -> title, preconditions -> custom_preconds, the step / expected pairs -> custom_steps_separated (Steps template), traceability -> refs. The blob is now a complete, runnable, verifiable case.
Limitations
References
Review rubric: worked examples
View source (opens in new window)Review rubric: worked examples
A weak case scored against the axes, then its rewrite re-scored to PASS. The axis definitions, Gate 0, scoring rules, and conventions live in the Review rubric section of the test-case-anatomy-reference SKILL.md.
A weak case, scored
The case as written:
ID: TC-07
Title: Test checkout
Preconditions: System is ready
Steps:
1. Log in and go to the cart
2. Enter a coupon
3. Click #btn-checkout-submit
4. Verify the order
Expected: Checkout works correctly
Refs: (blank)Gate 0: passes. Every required field has content, so the case is scorable.
| Axis | Verdict | Evidence |
|---|---|---|
| A1 Objective specificity | FAIL | "Test checkout" names a feature, not a behavior. A reader cannot tell which of the dozen things checkout does is under test, so they cannot tell whether the case passed for the right reason. |
| A2 Precondition executability | FAIL | "System is ready" is not a state. Ready with which account, which cart contents, which build, which coupon configured? Two testers will set up two different systems and get two different results. |
| A3 Step granularity | FAIL | Step 1 combines two interactions ("log in" and "go to the cart"). No step carries a paired expected result, so a failure at step 2 is indistinguishable from a failure at step 4. Step 4 leads with Verify, which names no interaction. |
| A4 Step abstraction match | WEAK | The objective is a business flow, but step 3 is a DOM selector. The case will break on a markup change that does not affect checkout behavior. |
| A5 Expected-result observability | FAIL | "Checkout works correctly" is not observable. There is no value, state, or message to compare against, so two testers can disagree about whether the case passed. |
| A6 Traceability validity | WEAK | Reference is blank and no exploratory justification is given. WEAK rather than FAIL: the case is still runnable, it just does not report coverage. |
Case verdict: FAIL. Four axes fail. This is not a case that needs polishing; it is a case that needs writing.
The rewrite
ID: CHECKOUT-TC-07
Title: Applies a 10 percent coupon to the order subtotal before tax
Preconditions:
- Account checkout-qa@example.com exists, is verified, and has an empty cart
- Coupon SAVE10 is active: 10 percent off subtotal, no minimum spend,
expires 2027-01-01
- Build web 4.12.0 on staging, Chrome 138, locale en-US, tax rate 8 percent
Inputs: SKU DEMO-001 at 100.00 USD, quantity 1, coupon SAVE10,
test card 4242 4242 4242 4242
Steps:
1. Sign in as checkout-qa@example.com
-> Account menu shows checkout-qa@example.com
2. Add SKU DEMO-001, quantity 1, to the cart
-> Cart badge shows 1; cart subtotal shows 100.00 USD
3. Open the cart and apply coupon SAVE10
-> Discount line shows 10.00 USD off; subtotal shows 90.00 USD
4. Complete payment with card 4242 4242 4242 4242
-> Confirmation shows order total 97.20 USD
(90.00 discounted subtotal plus 7.20 tax at 8 percent)
Postconditions: Order exists in status paid; the account's cart is empty
Refs: REQ-CHECKOUT-114 (percentage coupons apply before tax)Re-scored:
| Axis | Verdict | What changed |
|---|---|---|
| A1 | PASS | The title names one observable behavior (coupon applies before tax) and one verification. The ordering claim is the whole point of the case and is now visible in the title. |
| A2 | PASS | Account, coupon configuration, build, browser, locale, and tax rate are all named. A second tester reaches the same starting state. |
| A3 | PASS | Four steps, one interaction each, each with a paired expected result. A failure now localizes to a step. |
| A4 | PASS | Steps are phrased at the business layer the objective claims, with concrete inputs. No DOM selectors, because no DOM mechanic is under test. |
| A5 | PASS | Every expected result is a number or a string on screen. The arithmetic is shown, so the case doubles as its own oracle: a reviewer can check 90.00 plus 7.20 without opening the requirement. |
| A6 | PASS | Resolves to REQ-CHECKOUT-114, and the parenthetical says which clause of it. |
Case verdict: PASS.
One thing the rewrite cannot fix on its own: S1 and S2 are set-level. This case covers exactly one partition (a valid percentage coupon, no minimum spend). The review should therefore emit a follow-up list rather than declare coverage done: expired coupon, coupon below a minimum spend, coupon at exactly the minimum spend and one cent under it, and a coupon that would drive the subtotal below zero.
Tracker-schema map
View source (opens in new window)Tracker-schema map
Five common trackers each store the canonical test-case anatomy under different field names. Use this map when migrating cases between tools or when a template author must know the exact per-tracker field to write to. Sources for each tracker's API are listed in the parent SKILL.md References section.
TestRail
| Canonical field | TestRail field |
|---|---|
| Identifier | id (e.g., C1234) |
| Objective | title |
| Preconditions | custom_preconds |
| Inputs | (within custom_steps_separated[].content) |
| Steps | custom_steps_separated (Steps template) or custom_steps (Text template) |
| Expected results | custom_steps_separated[].expected |
| Postconditions | (custom field if defined) |
| Environment | custom_environment (custom field) or filter via refs |
| Traceability | refs (free text); template_id (Steps / Text / Exploratory) |
TestRail templates (template_id): Steps (1) / Text (2) / Exploratory (3). The Steps template enforces step-level structure; Text is freeform; Exploratory is for SBTM-style charters.
Xray (Atlassian)
Xray stores tests as Jira issues with Test issue type. Steps live in a separate sub-entity.
| Canonical field | Xray field |
|---|---|
| Identifier | Jira key (e.g., ENG-123) |
| Objective | Jira summary |
| Preconditions | Linked precondition (separate Jira issue type) |
| Steps | Test steps section (per testType: Manual); for Cucumber, Gherkin section; for Generic, free-text |
| Expected results | per-step expectedResult |
| Environment | Test execution testEnvironments (set per run) |
| Traceability | Jira issue links (Tests / TestedBy) |
Xray testType: Manual / Cucumber / Generic. Determines how steps are stored.
Zephyr Scale (Smart Bear)
| Canonical field | Zephyr field |
|---|---|
| Identifier | key (e.g., PROJ-T123) |
| Objective | name |
| Preconditions | precondition |
| Steps | testScript.steps[].description |
| Expected results | testScript.steps[].expectedResult |
| Environment | Configured per test cycle, not case |
| Traceability | issueLinks (Jira issues) |
Allure TestOps
| Canonical field | Allure TestOps field |
|---|---|
| Identifier | id (numeric, e.g., 1234) |
| Objective | name |
| Preconditions | precondition |
| Steps | scenario.steps (recursive - steps can have sub-steps) |
| Expected results | Within step expectedResult |
| Environment | tags (key=value pairs) + execution env |
| Traceability | relations (links to other cases / requirements) |
Qase
| Canonical field | Qase field |
|---|---|
| Identifier | id (within project; full ID is PROJ-1234) |
| Objective | title |
| Preconditions | preconditions |
| Steps | steps[].action |
| Expected results | steps[].expected_result |
| Environment | Custom fields |
| Traceability | links field |
Severity, priority, type (cross-platform)
All five trackers carry severity / priority / type fields. Each uses its own enum but they map similarly:
| Concept | TestRail | Xray | Zephyr Scale | Allure TestOps | Qase |
|---|---|---|---|---|---|
| Priority | priority_id (1-4) | Jira priority field | priority enum | Custom | priority enum (low/med/high) |
| Severity | Custom field | Custom field | severity enum (minor/normal/major/critical/blocker) | severity (default labels) | severity enum |
| Type | type_id (Functional, Performance, etc.) | testType (Manual/Cucumber/Generic) | testType (Manual/Automated) | Custom | type (functional/smoke/regression/etc.) |
| Automation status | custom_automation_type | Linked to automation results | automation field | Tags | automation (manual/automated/to-be-automated) |
Related skills
tcm-case-management
Test case management (TCM) across the five major platforms - TestRail, Xray, Zephyr Scale, Allure TestOps, and Qase - one tool-agnostic workflow for pre-execution case authoring and repository management: create and update cases, organise suites / sections / folders, attach structured steps with per-step expected results, link cases to requirements (Jira / Linear / GitHub), bulk import from CSV / JSON with idempotent re-runs, and sync from CI. The body works the workflow end to end against TestRail's API v2; references/ carries the per-vendor API specifics (auth model, endpoints, steps shape, enums, rate limits) for all five tools. Use for test case management in any of the five TCMs - authoring cases from a spec, bulk-importing legacy cases, migrating between tools, or mass-editing a case repository. Do NOT use for posting test-run results (pass/fail): result sync is the qa-test-reporting plugin's *-integration surface.
traceability-matrix-builder
Build-an-X workflow that produces a requirements-to-tests traceability matrix from a TCM case repository + a requirements source (Jira / Linear / GitHub Issues). Walks the author through (1) extracting requirements with stable IDs, (2) extracting cases + their refs, (3) computing coverage (which requirements have at least one test, which tests verify which requirements, orphaned cases / orphaned requirements), (4) emitting a CSV / Markdown / HTML matrix, and (5) producing an executive summary (X% requirement coverage, Y orphans, Z over-tested). Use for test coverage audits, finding requirements-coverage gaps, sprint-end coverage reviews, compliance documentation, and traceability in regulated industries.