Testing Fundamentals, Reframed for Automation · Lesson 3 of 5

Decision Tables & State Transitions

Some rules aren't a range of numbers — they're a mix of yes/no conditions. Two tidy tools make sure you never miss a combination, or a bad sequence. Both are just careful list-making.

By Shahriyar · Updated

The idea, in one line

When several yes/no conditions combine, write out every combination and its result. That grid is a decision table, and it stops you testing the happy path and calling it done.

How many rows?

See it work

In automation the table isn't a spreadsheet — it's just data: a list of rows fed to one test. New rule? Add a row.

▸ try it
# Decision table as data: 2 conditions -> 4 rows
# (in_window, item_returned, expected_action)
rules = [
    (True,  True,  "refund"),
    (True,  False, "reject"),
    (False, True,  "reject"),
    (False, False, "reject"),
]

def decide(in_window, item_returned):
    return "refund" if in_window and item_returned else "reject"

for in_window, returned, expected in rules:
    assert decide(in_window, returned) == expected
print(f"{len(rules)} rules covered")   # 4 rules covered

Read it top to bottom: you listed all four combinations, wrote the rule once, then checked the rule against every row. Nothing slips through.

Advanced — when order matters

Decision tables catch bad combinations. But some features have memory, where the same action means different things depending on what happened before. That's where state transition testing comes in.

Grounded in Guru99's Decision Table Testing guide (aligned with ISTQB)

All lessons in Testing Fundamentals, Reframed for Automation

  1. The Test Pyramid & Quadrants — What to Automate First
  2. Boundary Values & Equivalence Partitioning as Automation Inputs
  3. Decision Tables & State Transitions
  4. Risk-Based Testing — Deciding What NOT to Automate
  5. Shift-Left, Shift-Right & Your 1-Page Test Strategy