Test Case Design Techniques Explained (With Examples)

Testing without a systematic approach leads to redundant checks, missed defects, and wasted effort. When a tester relies solely on intuition, the resulting suite often covers obvious paths while ignor

January 08, 2026 · 18 min read · Testing Guides

Why Test Case Design Matters

Testing without a systematic approach leads to redundant checks, missed defects, and wasted effort. When a tester relies solely on intuition, the resulting suite often covers obvious paths while ignoring edge conditions that cause failures in production. Structured test‑case design techniques transform requirements into a compact, high‑signal set of scenarios that maximize defect detection per executed test. By applying equivalence partitioning, boundary value analysis, decision tables, state transition models, pairwise combinations, and error guessing, teams can:

The techniques described below are black‑box; they treat the system as a specification‑driven entity and do not require knowledge of internal code. They are most effective when applied early in the test‑design phase, before test scripts are written.

Core Black‑Box Techniques Overview

What Is Black‑Box Testing?

Black‑box testing derives test cases from the external behavior of a system—its inputs, outputs, and state transitions—without inspecting source code or internal architecture. The tester assumes the specification is correct and focuses on verifying that the implementation conforms to it.

Goals of Technique‑Based Design

Each technique serves a specific purpose:

TechniquePrimary GoalTypical Input DomainTypical Output Domain
Equivalence PartitioningReduce redundant input tests by grouping equivalent valuesFinite or infinite sets (e.g., numeric ranges, enumerations)Pass/Fail based on specification
Boundary Value AnalysisTarget errors that occur at the edges of input domainsSame as EP, with emphasis on min, max, just inside/outsidePass/Fail
Decision Table TestingCapture complex business rules with multiple conditionsDiscrete condition combinations (True/False)Action outcomes
State Transition TestingModel system behavior as a sequence of states and eventsStates and events (e.g., UI screens, protocol phases)Valid/invalid transitions
Pairwise TestingExercise interactions of pairs of parameters to catch most interaction defectsMulti‑parameter configuration spacesSystem response
Error GuessingLeverage tester experience to target likely fault locationsHeuristic‑based, often ad‑hocDefect detection

Understanding when each technique shines helps testers build a balanced suite that is both efficient and thorough.

Equivalence Partitioning (EP)

Fundamentals

EP divides the input domain of a component into partitions where the system is expected to behave identically for all members of a partition. If one value in a partition passes, the assumption is that all other values in that partition will also pass; similarly, a single failure indicates the whole partition is suspect. Partitions can be valid (values the system should accept) or invalid (values the system should reject).

The process:

  1. Identify each input variable and its specification (range, set, format).
  2. Create one valid partition for each specified condition and one invalid partition for each condition’s complement.
  3. Select a representative value from each partition to form a test case.

Worked Example: Login Form

Consider a web login with two fields: username (alphanumeric, 3‑15 characters) and password (minimum 8 characters, at least one digit).

InputSpecificationValid Partition(s)Invalid Partition(s)
Usernamealphanumeric, length 3‑15“abc123”, “User9”“ab” (too short), “user_name” (underscore), “averylongusernameexceedinglimit” (too long)
Password≥8 chars, ≥1 digit“Passw0rd”, “12345678”“password” (no digit), “123” (too short), “Pass!” (no digit, special char allowed? assume not)

From these partitions we derive test cases by picking one representative from each valid and invalid set. A minimal EP suite might look like:

TC IDUsernamePasswordExpected Result
1abc123 (valid)Passw0rd (valid)Login success
2ab (invalid)Passw0rd (valid)Username error
3averylongusernameexceedinglimit (invalid)Passw0rd (valid)Username error
4abc123 (valid)password (invalid)Password error
5abc123 (valid)123 (invalid)Password error
6abc123 (valid)Pass! (invalid)Password error

Only six test cases are needed to cover all partitions, versus testing every possible username/password combination, which would be infeasible.

Deriving Test Cases

When multiple inputs exist, the naive Cartesian product of partitions explodes. EP alone does not address interaction effects; it assumes independence. To keep the suite small, testers often combine EP with other techniques (e.g., decision tables or pairwise) for multi‑parameter scenarios.

Limitations and Mitigations

Boundary Value Analysis (BVA)

Fundamentals

BVA focuses on the values at the edges of input domains because defects frequently cluster there. For each input range [min, max], BVA generates test values: min, min+1, max‑1, max, and optionally values just outside the range (min‑1, max+1). When dealing with output boundaries or internal calculations, the same principle applies.

Worked Example: Age Field

A registration form accepts an age integer between 18 and 65 inclusive.

Boundary TypeValues
Valid min18
Valid min+119
Valid max‑164
Valid max65
Invalid min‑117
Invalid max+166

A robust BVA suite adds the “just outside” values to catch off‑by‑one errors in both directions. Test cases:

TC IDAgeExpected Result
118Accept
219Accept
364Accept
465Accept
517Reject (underage)
666Reject (overage)

If the system also validates that age must be numeric, we add non‑numeric tests (e.g., “eighteen”, “18.5”) as separate invalid partitions.

Robust BVA

Robust BVA extends the basic set by including multiple invalid values on each side (e.g., min‑2, min‑1, max+1, max+2) and sometimes worst‑case combinations when more than one input variable is present. For a single variable, the robust set is: {min‑2, min‑1, min, min+1, max‑1, max, max+1, max+2}.

When to Prefer BVA Over EP

BVA is often applied after EP to refine the test set around the borders of each partition.

Decision Table Testing

Fundamentals

Decision tables excel when business rules involve multiple conditions that combine to produce distinct actions. Each column of the table represents a unique combination of condition values (True/False) and the corresponding expected actions. The technique ensures that every relevant condition combination is considered, reducing the chance of missing a rule.

Steps:

  1. List all conditions (inputs) that influence the outcome.
  2. List all actions (outputs) the system may perform.
  3. Determine the number of possible condition combinations (2ⁿ for n binary conditions).
  4. Fill the table, marking each condition as T or F and specifying the resulting action(s).
  5. Eliminate impossible or irrelevant columns (e.g., mutually exclusive conditions).
  6. Derive one test case per remaining column.

Worked Example: Discount Eligibility

An e‑commerce site applies discounts based on three factors:

Actions:

The decision table (showing only feasible columns) is:

C1C2C3A1A2A3A4
RLNX
RLYX
RHNX
RHYX
PLNX
PLYX
PHNX
PHYX

(Explanation: Premium customers never receive a discount on low orders; high‑order premium customers get 10%; coupon adds an extra 5% up to a maximum of 15%.)

Each column yields a test case:

TC IDCustomer TypeOrder AmountCouponExpected Discount
1RegularLowNo0%
2RegularLowYes5%
3RegularHighNo10%
4RegularHighYes15%
5PremiumLowNo0%
6PremiumLowYes5%
7PremiumHighNo10%
8PremiumHighYes0% (coupon not applicable)

Building the Table

When conditions are not strictly binary (e.g., three‑level priority), expand each condition into multiple binary sub‑conditions or use extended decision tables that allow multiple values per condition cell. Tools like DTable or simple spreadsheets can automate the generation of all combinations and the removal of infeasible rows.

Automation Tips

State Transition Testing

Fundamentals

State transition testing models a system as a finite set of states and events (or triggers) that cause transitions between states. Each transition may have an associated action or output. The technique is ideal for protocols, UI workflows, and any component where behavior depends on prior history.

A state transition diagram (or state table) captures:

Test cases are sequences of events that traverse specific paths, including valid transitions, invalid transitions, and loops.

Worked Example: Shopping Cart Lifecycle

Consider a simplified cart with states: Empty, ItemsAdded, CheckoutStarted, PaymentPending, OrderConfirmed, OrderCancelled. Events: AddItem, RemoveItem, ProceedToCheckout, SubmitPayment, CancelOrder, Timeout.

State Table (excerpt):

Current StateEventGuardNext StateAction
EmptyAddItemitemId validItemsAddedShow item in cart
ItemsAddedRemoveItemcart not emptyEmpty if last itemUpdate cart
ItemsAddedProceedToCheckoutcart not emptyCheckoutStartedShow checkout page
CheckoutStartedSubmitPaymentpayment validPaymentPendingCall payment gateway
PaymentPendingSubmitPaymentpayment invalidCheckoutStartedShow error
PaymentPendingTimeoutOrderCancelledRelease inventory
PaymentPendingSubmitPaymentpayment validOrderConfirmedSend confirmation email
AnyStateCancelOrderOrderCancelledClear cart

From this table we can derive test sequences:

Each sequence becomes a test case; assertions verify that the system ends in the expected state and performs the expected actions (e.g., email sent, inventory updated).

Drawing the Diagram

Tools such as draw.io, Microsoft Visio, or PlantUML enable quick creation of state diagrams. PlantUML snippet for the cart:


[*] --> Empty
Empty --> ItemsAdded : AddItem
ItemsAdded --> Empty : RemoveItem[last]
ItemsAdded --> CheckoutStarted : ProceedToCheckout
CheckoutStarted --> PaymentPending : SubmitPayment[valid]
PaymentPending --> OrderConfirmed : SubmitPayment[valid]
PaymentPending --> CheckoutStarted : SubmitPayment[invalid]
PaymentPending --> OrderCancelled : Timeout
CheckoutStarted --> OrderCancelled : CancelOrder
OrderConfirmed --> [*]
OrderCancelled --> [*]

Generating Test Sequences

Automated test generation can be performed with model‑based testing tools (e.g., GraphWalker, Yakindu) that consume the state model and emit executable scripts.

Pairwise (Combinatorial) Testing

Fundamentals

Pairwise testing assumes that most defects are triggered by interactions of at most two parameters. Instead of testing the full Cartesian product of all parameter values, it selects a subset of combinations that guarantees every pair of parameter values appears together in at least one test case. This often reduces the test count dramatically while preserving high defect detection power.

The problem is NP‑hard, but greedy algorithms (e.g., PICT, Allpairs) produce near‑optimal results quickly.

Worked Example: Configuration Matrix

A mobile app must be tested across three dimensions:

Full factorial: 4 × 3 × 3 = 36 combinations.

Using a pairwise tool (e.g., pip install pairwise or PICT), we obtain a set of 12 test cases that cover all pairs:

TCOSNetworkLanguage
1Android 11Wi‑FiEnglish
2Android 114GSpanish
3Android 115GJapanese
4Android 12Wi‑FiSpanish
5Android 124GJapanese
6Android 125GEnglish
7iOS 14Wi‑FiJapanese
8iOS 144GEnglish
9iOS 145GSpanish
10iOS 15Wi‑FiEnglish
11iOS 154GJapanese
12iOS 155GSpanish

Verification: each OS value appears with each Network value at least once, each OS with each Language, and each Network with each Language.

Tools and Algorithms

Example using Allpairs in Python:


from allpairs import allpairs

params = [
    ["Android 11", "Android 12", "iOS 14", "iOS 15"],
    ["Wi-Fi", "4G", "5G"],
    ["English", "Spanish", "Japanese"]
]

for combo in allpairs(params):
    print(combo)

Limitations

Error Guessing and Experience‑Based Techniques

Fundamentals

Error guessing relies on the tester’s knowledge of common failure modes, past defects, and system specifics to devise targeted tests. While less formal than the other techniques, it excels at catching edge cases that specifications overlook, such as off‑by‑one loops, race conditions, or usability pitfalls.

Common sources for error guessing:

Worked Example: File Upload

A web service lets users upload profile pictures. Specification: accept JPEG/PNG, max size 5 MB, dimensions 200 × 200 px to 4000 × 4000 px.

From experience, a tester might guess the following failure points:

  1. Empty file – zero‑byte upload.
  2. File with correct extension but wrong content – rename a .txt to .jpg.
  3. File exactly at size limit – 5 MB + 1 byte.
  4. File with dimensions just outside bounds – 199 × 199 px, 4001 × 4001 px.
  5. Concurrent uploads – two simultaneous requests from the same session.
  6. Filename with special characters.., /, Unicode emojis.
  7. MIME type spoofing – set Content-Type: image/jpeg for a PDF.

Each guess becomes a test case, often combined with other techniques (e.g., boundary values for size).

Combining with Structured Techniques

Error guessing is most effective when used after systematic techniques have covered the main partitions. The tester reviews the generated test set, identifies gaps (e.g., missing concurrency or security checks), and adds focused guesses. This hybrid approach yields a suite that is both comprehensive and agile.

Selecting the Right Technique

Decision Matrix

Choosing a technique depends on the nature of the input domain, the presence of complex business rules, and the importance of stateful behavior. The following matrix helps map scenario characteristics to recommended techniques:

Scenario CharacteristicBest Fit Technique(s)Rationale
Simple numeric or enumerated input, independent fieldsEP + BVAPartitions and boundaries capture most faults.
Multiple interdependent conditions affecting outputDecision TableEnsures every condition combination is examined.
Behavior depends on prior actions or eventsState TransitionModels histories and validates transitions.
Many configurable parameters (OS, device, locale, etc.)Pairwise (or higher‑order t‑way)Controls combinatorial explosion.
No clear specification, high reliance on tester intuitionError Guessing + ExploratoryTargets known failure patterns.
Mixed (e.g., a form with fields, business rules, and workflow)Combine EP/BVA → Decision Table → State Transition → Pairwise → Error GuessingLayered approach addresses each aspect.

Technique Combination Patterns

  1. EP → BVA → Pairwise – Start with EP to identify partitions, refine each partition’s borders with BVA, then apply pairwise across the resulting parameters to catch interaction defects.
  2. Decision Table → State Transition – Use a decision table to define actions for each condition set, then map those actions onto state transitions to verify that the system reaches the correct state after processing the rules.
  3. Pairwise → Error Guessing – Generate a pairwise set for configuration testing, then add error‑guessing tests for known platform‑specific bugs (e.g., Android WebView quirks).

The key is to avoid redundancy: each added technique should target a risk not already covered by the previous ones.

From Design to Execution: Manual and Automated Approaches

Manual Test Scripts

When tests are low‑volume or require human judgment (e.g., usability, exploratory), manual execution remains valuable. A manual test script derived from EP/BVA might look like:


Test ID: LOGIN-03
Precondition: User is on login page.
Steps:
1. Enter username "ab" (2 chars, invalid).
2. Enter password "Passw0rd".
3. Tap Login.
Expected Result: Error message "Username must be at least 3 characters."

Manual execution allows the tester to observe subtle UI feedback, such as toast messages or focus shifts, that automated scripts might overlook unless explicitly asserted.

Automated Script Generation (Appium, Playwright)

For regression and CI pipelines, converting designed cases into automated scripts ensures repeatability. Below are concise examples for the login form using Appium (Android) and Playwright (Web).

Appium Java (Android)


import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import org.openqa.selenium.By;
import org.testng.annotations.*;

public class LoginTest {
    private AppiumDriver<MobileElement> driver;

    @BeforeMethod
    public void setUp() {
        // capabilities omitted for brevity
        driver = new AppiumDriver<>(new URL("http://localhost:4723/wd/hub"), caps);
    }

    @Test(dataProvider = "loginData")
    public void testLogin(String user, String pass, boolean shouldPass) {
        driver.findElement(By.id("username")).sendKeys(user);
        driver.findElement(By.id("password")).sendKeys(pass);
        driver.findElement(By.id("loginBtn")).click();

        if (shouldPass) {
            assert driver.findElement(By.id("homeScreen")).isDisplayed();
        } else {
            assert driver.findElement(By.id("errorMsg")).isDisplayed();
        }
    }

    @DataProvider
    public Object[][] loginData() {
        return new Object[][]{
            {"abc123", "Passw0rd", true},
            {"ab", "Passw0rd", false},
            {"averylongusernameexceedinglimit", "Passw0rd", false},
            {"abc123", "password", false},
            {"abc123", "123", false},
            {"abc123", "Pass!", false}
        };
    }

    @AfterMethod
    public void tearDown() {
        if (driver != null) driver.quit();
    }
}

Playwright TypeScript (Web)


import { test, expect } from '@playwright/test';

test.describe('Login form', () => {
  const testCases = [
    { user: 'abc123', pass: 'Passw0rd', pass: true },
    { user: 'ab', pass: 'Passw0rd', pass: false },
    { user: 'averylongusernameexceedinglimit', pass: 'Passw0rd', pass: false },
    { user: 'abc123', pass: 'password', pass: false },
    { user: 'abc123', pass: '123', pass: false },
    { user: 'abc123', pass: 'Pass!', pass: false }
  ];

  for (const {user, pass, pass: shouldPass} of testCases) {
    test(`login with user=${user}, pass=${pass}`, async ({ page }) => {
      await page.goto('https://example.com/login');
      await page.fill('#username', user);
      await page.fill('#password', pass);
      await page.click('#loginBtn');

      if (shouldPass) {
        await expect(page.locator('#homeScreen')).toBeVisible();
      } else {
        await expect(page.locator('#errorMsg')).toBeVisible();
      }
    });
  }
});

Both snippets illustrate how a data‑driven approach maps directly to the EP-derived test matrix. The same principle applies to decision tables (iterating over rows), state transitions (executing event sequences), and pairwise configurations (varying OS/network/language parameters).

Integrating with CI

Edge Cases That Appear Only in Production

Even the most meticulously designed test suite can miss defects that only manifest under real‑world load, timing, or environmental conditions. Recognizing these categories helps testers augment their suites with targeted probes.

Timing and Concurrency

Mitigation: incorporate stress and soak tests, use tools like Gatling or k6 to simulate concurrent users, and inject artificial delays (e.g., Thread.sleep or network throttling) in automated scripts.

Localization and Data Variants

Mitigation: include locale‑specific data sets in EP/BVA (e.g., test with “JP” locale, Japanese characters, and yen symbol). Use pseudo‑localization to uncover hard‑coded strings.

Device‑Specific Quirks

Mitigation: run a subset of tests on a device farm (e.g., Firebase Test Lab, AWS Device Farm) covering a matrix of OS versions, screen sizes, and manufacturers. Pairwise testing can help select a representative device set.

Autonomous Exploration as a Complement

How SUSA Explores

SUSA (SUSATest) is an autonomous QA agent that, given an APK or a web URL, builds a model of the application’s reachable states by interacting with UI elements, filling forms, handling dialogs, and navigating flows. It employs a blend of guided randomness and heuristic-driven exploration (e.g., favoring unexplored elements, respecting accessibility hints). Each run produces:

Feeding Discovered Flows Back into Designed Cases

The output of SUSA can be used to enrich manually designed test suites in two ways:

  1. Gap Analysis – Compare the set of flows discovered by SUSA against the flows covered by existing test cases. Any

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