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
parametrizeconverts 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.
| Aspect | Without Decision Table | With Decision Table |
|---|---|---|
| Managing combinations | Tracked mentally or in bullet points | All patterns visible at a glance in the table |
| Risk of missed cases | High — gaps are easy to miss | Low — coverage is guaranteed by the table |
| Team sharing | Requires verbal explanation, easily misunderstood | Share the table directly — easy to review |
| Converting to automation | Design and code tend to drift apart | Feeds 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
| 💡 How to Read It
| ||||||||||||||||||||||||||||||
| Part | Content | Example |
|---|---|---|
| Conditions | The input conditions being tested | Is the ID correct? / Is the password correct? |
| Actions | Expected results for each combination | Login 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
| Step | What to Do |
|---|---|
| STEP 1 | Extract “conditions” from the spec (rewrite each as a Yes/No question) |
| STEP 2 | Calculate the total number of patterns (n Yes/No conditions = 2ⁿ patterns) |
| STEP 3 | Fill in the expected action (result) for each pattern |
| STEP 4 | Remove impossible combinations to reduce the total case count |
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 / Action | Case 1 | Case 2 | Case 3 | Case 4 |
|---|---|---|---|---|
| Condition ①: Username correct | Yes | Yes | No | No |
| Condition ②: Password correct | Yes | No | Yes | No |
| 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 / Action | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 |
|---|---|---|---|---|---|---|---|---|
| Premium member | Y | Y | Y | Y | N | N | N | N |
| Coupon used | Y | Y | N | N | Y | Y | N | N |
| Purchase over $30 | Y | N | Y | N | Y | N | Y | N |
| → Discount rate | 30% | 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.
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_msgSample 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 ===========================⚠️ 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).
📖 Related Articles
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.

