# ISTQB Techniques — TC Count Expansion Reference

**Purpose:** Define canonical TC count rules per ISTQB technique for API testing (Layer 2 → Layer 3 expansion). This file owns the *how many TCs* question for API tests. For functional/UI TC counts → `tc-generation-strategy.md § Layer 3`. For technique selection (which technique per field/category) → `test-design.md § TP Category → Test Approach Mapping` (functional) or `api-test-strategy.md § Layer 2` (API).

**Used by:** `/tas-apitest-plan` Phase 3 (Detail) — TC count expansion per endpoint

---

## BVA — Boundary Value Analysis

**When:** Numeric, date, string-length fields with documented min/max constraints.

**Standard 4-point expansion:**

| TC | Value | Modifier | Expected |
|---|---|---|---|
| BVA·min-1 | min − 1 | `_E` (error) | Reject: below minimum |
| BVA·min | min | `_H` (happy) | Accept |
| BVA·max | max | `_H` (happy) | Accept |
| BVA·max+1 | max + 1 | `_E` (error) | Reject: above maximum |

**Count:** 4 TCs per constrained field.

**Special cases:**

| Case | Rule |
|---|---|
| Unbounded min (no minimum) | Drop BVA·min-1 and BVA·min → reduce to BVA·max and BVA·max+1 (2 TCs) |
| Unbounded max (no maximum) | Drop BVA·max and BVA·max+1 → reduce to BVA·min-1 and BVA·min (2 TCs) |
| Integer-only field | Values are integers; BVA·min-1 = min − 1 integer (no decimals) |
| Response time SLA | BVA on milliseconds: below-p95, at-p95-boundary, above-p95 (3-point, not 4, as no lower-bound) |

---

## EP — Equivalence Partitioning

**When:** Enum fields, categorical inputs, valid/invalid partitions, required/optional.

**Standard expansion per partition class:**

| Partition | TC count | Modifier |
|---|---|---|
| Valid partition | 1 TC | `_H` |
| Invalid partition | 1 TC per distinct invalid class | `_E` |

**Count:** 1 valid + 1 per distinct invalid class (minimum 2 TCs total).

**Common partition classes:**

| Field type | Partitions |
|---|---|
| Enum | 1 valid value from list + 1 value not in list + 1 empty/null |
| Required field | Present+valid + Absent/null + Empty string (3 partitions) |
| Optional field | Absent (default behavior) + Present+valid + Present+invalid |
| String format (email, phone, UUID) | Valid format + Invalid format + Empty |
| Nested object | Full object + Empty object `{}` + null |
| Array | Non-empty (1 item) + Empty array `[]` + null |

---

## Decision Table Testing

**When:** 2+ independent conditions produce different outcomes (business logic branching).

**Expansion:**
- List all condition combinations that produce distinct outcomes
- 1 TC per distinct outcome row
- Collapse equivalent rows (same outcome regardless of one condition = merge)

**Count:** 1 TC per distinct outcome (not per all possible combinations — combinatorial explosion avoided by outcome-based grouping).

**Example:**
```
Conditions: [User role: Admin | Standard] × [Resource owned: Yes | No]
Outcomes:
  Admin + Any ownership   → 200 OK           (1 TC)
  Standard + Owned        → 200 OK           (merged with above if identical response)
  Standard + Not owned    → 403 Forbidden    (1 TC)
→ 2 TCs (not 4)
```

---

## State Transition Testing

**When:** Endpoint or resource has documented status progression (e.g. Draft → Submitted → Approved → Rejected).

**Expansion:**
- 1 TC per valid transition (happy path)
- 1 TC per invalid transition (attempting forbidden state jump)

**Count:** (valid transitions) + (invalid transitions to test)

**Depends chain:** Use `Depends:` to chain TCs in execution order — a TC testing transition A→B depends on TC that established state A.

**Example:**
```
States: Draft → Submitted → Approved | Rejected
Valid transitions: (Draft→Submitted), (Submitted→Approved), (Submitted→Rejected)  = 3 TCs
Invalid transitions: (Draft→Approved skip), (Approved→Submitted back)              = 2 TCs
Total: 5 TCs with Depends chain
```

---

## Use Case Flow

**When:** Happy path + alternative flows + error flows for a complete user journey through the API.

**Expansion:**
- 1 TC per distinct flow variant (Main, Alt, Error)
- Main flow = full happy path through all steps
- Alt flow = legitimate variation (different input subset, different role)
- Error flow = expected error response at a specific step

**Count:** 1 per distinct flow. Does NOT expand exponentially — flows identified at L1 scope.

---

## Error Guessing

> **Functional/UI context:** For manual functional testing, Error Guessing patterns (double-click, browser back mid-flow, concurrent tabs) are defined in [test-design.md § Functional Test Techniques](../../rules/qa/test-design.md). This section covers API context only.

**When:** Known error-prone areas based on API design patterns or risk tags.

**Expansion:**
- 1 TC per known risk scenario

**Common patterns:**
- Race condition on concurrent POST creating same unique resource → 1 TC (concurrent requests)
- Idempotency: same POST with same idempotency-key sent twice → 1 TC
- Large payload: request body at upper size limit → 1 TC
- Malformed JSON: unparseable body → 1 TC (cross-cutting, shared)

---

## TC Count Summary Table (API context)

> Dedup keys per technique → `api-test-strategy.md § API-Specific Dedup Extensions` (this file owns count only, not dedup — per `verification-layers.md § 8.5`).

| Technique | Trigger | Canonical count |
|---|---|---|
| BVA | Numeric/date/string with min+max | 4 TCs |
| BVA (one-sided) | Only min or only max | 2 TCs |
| EP | Enum / categorical / required | 1 valid + 1 per invalid class |
| Decision Table | 2+ conditions → branching | 1 per surviving row after full-enumeration + proven collapse |
| State Transition | Status field / workflow | (valid-transition table rows) + (sampled invalid pairs) |
| Use Case Flow | Endpoint journey | 1 per flow variant |
| Error Guessing | Known risk pattern | 1 per known scenario |

---

## Assertion Depth per TC

Each generated TC must assert:

| Response element | Required assertion |
|---|---|
| Status code | Exact match (`pm.response.to.have.status(N)`) |
| Response body schema | All required fields present; field types correct |
| Error message | For error TCs: specific error code or message text |
| Response headers | `Content-Type: application/json` on 2xx JSON; `Location` on POST→201; `Retry-After` on 429 |
| Response time | For Perf TCs only: `pm.expect(pm.response.responseTime).to.be.below(N)` |
| Side effects | For state-changing endpoints: follow-up GET to verify created/updated/deleted state |

**One TC = one distinct assertion point.** Do not merge 3 unrelated assertions into 1 TC.
