What Is Decision Table Testing? How to Build One with Real Examples | Condition Combination Testing + pytest

test-automation

Decision table testing is a test design technique that organizes multiple conditions and their combinations into a table format to design test cases. It’s especially effective for verifying business rules where multiple conditions interact — login authentication, permission management, and discount logic are classic examples.

Decision tables let you organize all combinations of multiple conditions without gaps or overlaps — eliminating the “we forgot to test that combination” problem at its root.

📌 Who This Article Is For

  • QA engineers and developers learning decision table testing for the first time
  • Anyone struggling to organize test cases when multiple conditions are involved
  • Those who want a systematic approach to testing business logic and permission management
  • Those studying for ISTQB and want to understand decision tables

✅ What You’ll Learn

  • The concept behind decision tables and how to build one
  • How to apply them to login and permission management scenarios common in real projects
  • How to combine them with pytest’s parametrize for automated testing

👤 About the Author

Written by Yoshi, a QA and test automation engineer with 15+ years of hands-on experience. Decision tables are a technique used daily for complex test design involving business logic. Code is publicly available on GitHub: github.com/YOSHITSUGU728/automated-testing-portfolio

“When two or more conditions interact, I lose track of which combinations need to be tested” — this is something every QA engineer has experienced.

  • Test cases multiply explosively as conditions increase
  • It becomes unclear which combinations have and haven’t been tested
  • “We never tested that pattern” — missed cases slip through

Decision table testing solves these problems. This article covers everything from the concept to building tables, real examples, and applying them in pytest.

📌 Key Takeaways

  • A test design technique that maps conditions (rows) against cases (columns) to list every combination in one table
  • 2 conditions = 4 patterns, 3 conditions = 8 patterns — but impossible combinations can be removed to keep things lean
  • Passing the table directly to pytest’s parametrize converts your design into automated tests instantly

What Is Decision Table Testing?

Decision table testing organizes the relationship between “conditions (inputs)” and “actions (expected results)” in a table format. Because it systematically captures all condition combinations, it’s widely used for testing complex business logic. It’s also known as a “cause-effect table” or “decision table.”

For example, testing a discount process with two conditions — “user type (standard / premium)” and “coupon availability (yes / no)” — a decision table lets you organize all 4 patterns (2×2) without missing a single one.

AspectWithout Decision TableWith Decision Table
Managing combinationsTracked mentally or in bullet pointsAll patterns visible at a glance in the table
Risk of missed casesHigh — gaps are easy to missLow — coverage is guaranteed by the table
Team sharingRequires verbal explanation, easily misunderstoodShare the table directly — easy to review
Converting to automationDesign and code tend to drift apartFeeds directly into parametrize

Decision Table Structure and How to Build One

A decision table consists of two parts: the Conditions section and the Actions section.

📋 Basic Decision Table Structure

Case 1Case 2Case 3Case 4
【Conditions】
ID correct?YYNN
PW correct?YNYN
【Actions】
Login succeeds

💡 How to Read It

  • Rows: Conditions (inputs) and actions (expected results)
  • Columns: Test case numbers
  • Y/N: Whether each condition is true or false
  • ✅/❌: Whether the action fires for that case
  • 2 conditions → 4 cases (2²) is the baseline
PartContentExample
ConditionsThe input conditions being testedIs the ID correct? / Is the password correct?
ActionsExpected results for each combinationLogin succeeds / Error message shown

Benefits of Decision Tables

  • No missed combinations: All patterns are laid out in the table — gaps are impossible to miss
  • Eliminates test case oversights: Moves from “testing by feel” to systematic coverage
  • Easy team reviews: QA and dev share a common view of the logic in table form
  • Converts directly to automation: Feeds straight into pytest’s parametrize

How to Build One — Step by Step

StepWhat to Do
STEP 1Extract “conditions” from the spec (rewrite each as a Yes/No question)
STEP 2Calculate the total number of patterns (n Yes/No conditions = 2ⁿ patterns)
STEP 3Fill in the expected action (result) for each pattern
STEP 4Remove impossible combinations to reduce the total case count
💡 Pattern Count Reference: When all conditions are Yes/No (true/false), n conditions produce 2ⁿ patterns. 2 conditions = 4 patterns · 3 = 8 · 4 = 16 · 5 = 32. For 6 or more conditions, consider combining with pairwise testing.

Example ①: Login Processing Decision Table

The most common example — a login process decision table. The two conditions are “Is the username correct?” and “Is the password correct?”

Condition / ActionCase 1Case 2Case 3Case 4
Condition ①: Username correctYesYesNoNo
Condition ②: Password correctYesNoYesNo
Action: Login succeeds
Action: Error message shown

This table clearly produces 4 test cases. Cases 2, 3, and 4 all result in errors — but since the error messages differ (“username not found” vs “wrong password” vs “both wrong”), all three cases should be run separately.

Example ②: Discount Logic Decision Table (3 Conditions)

With 3 conditions the pattern count grows to 8. Here’s an example with “premium membership”, “coupon used”, and “purchase over $30” as conditions that determine a discount rate.

Condition / ActionC1C2C3C4C5C6C7C8
Premium memberYYYYNNNN
Coupon usedYYNNYYNN
Purchase over $30YNYNYNYN
→ Discount rate30%25%20%15%15%10%5%0%

A quick glance reveals that C4 (premium, no coupon, under $30 = 15%) and C5 (non-premium, coupon, over $30 = 15%) produce the same discount rate. Spotting these “same-result cases” and consolidating them to reduce test count is another benefit of decision tables.

💡 Pro Tip: Cases with identical actions (expected results) can be merged to reduce test count. Combining C4 and C5 cuts 8 cases down to 7. That said, if error messages or downstream behavior could differ between cases, merging is risky — always verify the full expected result before consolidating.

Applying Decision Tables to pytest

Test cases designed with a decision table map directly onto pytest’s @pytest.mark.parametrize. Here’s the login process decision table implemented in pytest.

First, set up the login function being tested.

def login(user_id: str, password: str) -> dict:
    """Login function (sample)"""
    VALID_ID = "test_user"
    VALID_PW = "secret_pass"

    if user_id == VALID_ID and password == VALID_PW:
        return {"success": True, "message": "Login successful"}
    elif user_id != VALID_ID:
        return {"success": False, "message": "Username not found"}
    else:
        return {"success": False, "message": "Incorrect password"}

Next, implement all 4 decision table cases directly as parameters.

import pytest

# All 4 decision table cases parametrized directly
@pytest.mark.parametrize("user_id, password, expected_success, expected_msg", [
    # Case 1: correct ID + correct PW → success
    ("test_user",  "secret_pass", True,  "Login successful"),

    # Case 2: correct ID + wrong PW → failure
    ("test_user",  "wrong_pass",  False, "Incorrect password"),

    # Case 3: wrong ID + correct PW → failure
    ("wrong_user", "secret_pass", False, "Username not found"),

    # Case 4: wrong ID + wrong PW → failure
    ("wrong_user", "wrong_pass",  False, "Username not found"),
])
def test_login(user_id, password, expected_success, expected_msg):
    result = login(user_id, password)
    assert result["success"] == expected_success
    assert result["message"] == expected_msg

Sample Execution Output

$ pytest test_login.py -v

========================= test session starts ==========================
collected 4 items

test_login.py::test_login[test_user-secret_pass-True-Login successful]   PASSED [ 25%]
test_login.py::test_login[test_user-wrong_pass-False-Incorrect password] PASSED [ 50%]
test_login.py::test_login[wrong_user-secret_pass-False-Username not found] PASSED [ 75%]
test_login.py::test_login[wrong_user-wrong_pass-False-Username not found]  PASSED [100%]

========================== 4 passed in 0.12s ===========================
💡 Pro Tip: The best practice in production is to build the decision table first in a spreadsheet, get it reviewed, then translate it into code. Adding comments like “Case 1–4” makes it easy to trace the relationship between the table and the code later.

⚠️ 4 Common Pitfalls in Decision Table Testing

Here are the mistakes that are easy to make when building decision tables in practice.

① Building the table without converting conditions to Yes/No first

Every condition in a decision table must be answerable with Yes or No. A condition like “user type” that has multiple values needs to be reframed as “Is the user a premium member? (Yes/No)” before using it. Skipping this step throws off the pattern count and creates gaps.

② Forgetting to remove impossible combinations — inflating the test count

Some combinations simply can’t occur — for example, “coupon already applied” and “no coupon code entered” can’t both be true simultaneously. Leaving these in bloats the test count unnecessarily. After building your table, always ask “can this actually happen?” and remove the impossible cases.

③ Merging same-result cases too aggressively and missing error differences

Even when the action (expected result) looks the same, the error message content or downstream behavior may differ. Merging cases just because “both result in an error” can cause you to miss the fact that “username not found” and “incorrect password” should show different messages. Always verify the full expected result before merging.

④ Too many conditions — the table becomes unmanageable

6 conditions = 64 patterns, 7 = 128. At this scale a decision table alone can’t be managed effectively. For 5 or more conditions, consider combining with pairwise testing to reduce pattern count, or split the table into multiple smaller ones grouped by topic.

FAQ

Q. When should I use decision table testing?

Decision tables are best suited for test design where multiple conditions combine to determine the result — login authentication, permission management, pricing logic, and discount calculations are all good candidates. When there’s only a single condition, equivalence partitioning or boundary value analysis will give you a simpler design.

Q. What’s the difference between decision tables and pairwise testing?

Decision tables cover all combinations of conditions. Pairwise testing reduces the test count by ensuring every pair of parameters is covered at least once. For 5 or more conditions, decision tables alone can produce an explosion of patterns — combining them with pairwise testing is a common production approach.

Q. How do I choose between decision tables and equivalence partitioning / boundary value analysis?

Equivalence partitioning and boundary value analysis are for verifying the range of values for a single input field. Decision tables are for verifying combinations of multiple conditions. In practice both are often used together — EP/BVA on individual form fields, decision tables on the business logic that governs those fields.

Q. What if a condition has more than two values (not just Yes/No)?

For multi-value conditions like “membership tier: standard / silver / gold,” decompose them into Yes/No questions: “Silver tier or above? (Y/N)” and “Gold tier? (Y/N).” Alternatively, for a 3-value condition you can use 3 columns (standard / silver / gold) arranged vertically — both approaches are valid.

Q. How much do I need to understand for ISTQB?

ISTQB Foundation Level tests “how to read and build a basic decision table.” If you can confidently handle the login example in this article (2 conditions, 4 patterns), you’re at the passing level. Also make sure you can calculate the number of patterns from the number of conditions (n conditions = 2ⁿ patterns).

In production, a common workflow is to build the decision table in a spreadsheet, get it reviewed by both QA and dev, then convert it to pytest’s parametrize. Separating design from implementation makes the table reviewable by both teams — a meaningful advantage in collaborative environments.

📋 Summary

  • Decision tables list every combination of conditions (rows) × cases (columns) in one place
  • n conditions = 2ⁿ patterns (for Yes/No conditions) — remove impossible and duplicate cases to optimize test count
  • Most effective for login, permission management, and discount logic — any business rule with multiple interacting conditions
  • pytest parametrize pairs perfectly — your design table converts directly into automated tests
  • For 5 or more conditions, consider combining with pairwise testing

Decision tables turn the “combinations you were tracking mentally” into something visible — bringing missed cases close to zero. Start by building a 2–3 condition table for a login process or permission check you already work with. That’s the fastest way to make it click.

Copied title and URL