Decision Table Testing

8 min read

Some features behave differently depending on a combination of conditions. A shipping engine might offer free delivery if the order is over £50 and the customer is a member and the destination is in the UK — but charge a fee if any one of those is false. The bugs almost always come from a missed combination — a rule nobody enumerated. Decision tables force every combination into the open. This lesson teaches the technique on a real shipping discount scenario.

What a decision table actually is

A decision table has three sections:

  • Conditions — the inputs that affect behaviour. Yes/no questions are easiest: "Is the order over £50?", "Is the customer a member?", "Is the delivery address in the UK?"
  • Actions — the outcomes the system can produce. "Free shipping," "10% discount," "Standard rate," etc.
  • Rules — each combination of conditions and the action that should result. With three yes/no conditions, you have 2³ = 8 rules.

A complete decision table is the simplest, most defensible artefact you can hand a developer when behaviour depends on combinations. Either you both agree on the table or you have surfaced a real disagreement about the spec — both outcomes are useful.

Building one step by step

Take the shipping discount example. Three conditions, three possible actions, and the team thinks the rules are obvious. Write them down anyway.

  1. List conditions. Order over £50? (Y/N), Member? (Y/N), UK delivery? (Y/N).
  2. List actions. Free shipping, 10% discount, Standard rate.
  3. Enumerate every combination. With 3 yes/no conditions, that is 8 rows. Number them.
  4. Fill in the expected action for each row. This is where the team has to decide — and where disagreements appear.
#Over £50?Member?UK?Action
1YYYFree shipping
2YYN10% discount
3YNYFree shipping
4YNNStandard rate
5NYY10% discount
6NYNStandard rate
7NNYStandard rate
8NNNStandard rate

The act of filling in the rightmost column is what surfaces the bugs the spec missed. "Wait — does a member with a £20 UK order really get 10% off, or only on members-only items?" That kind of question is exactly what a decision table extracts from a vague spec.

Try it: predict the outcome

The exercise below gives you the rules above with the outcomes hidden. Choose the action for each rule, then check.

Shipping discount — predict the action

Apply the rules above. Each row is one combination of conditions; choose the expected action.

Order over £50?Member?UK delivery?Outcome
YesYesYes
YesYesNo
YesNoYes
YesNoNo
NoYesYes
NoYesNo
NoNoYes
NoNoNo

 

If you got even one row wrong, that is the entire point. The rules feel obvious in prose and yet the brain trips on combinations. Now imagine the same code being implemented from prose by a developer working alone.

Reducing the table

Real-world tables can be shrunk before you derive test cases. Two reduction tactics matter:

  • Impossible combinations. "Customer is a member" and "Customer is anonymous" are mutually exclusive — never enumerate that row at all.
  • Don't-care conditions. If rules 7 and 8 produce the same action regardless of "Member?", you can collapse them into a single row with a dash: (N, –, N) → Standard rate. The dash signals "we tested that this condition does not affect the outcome here."

Reduce after you have written the full table — never before. A row that "obviously" has the same outcome as another often turns out to differ on closer reading.

Deriving test cases

Each row of the final table becomes one test case. The work that remains is mostly clerical: name the test, write the preconditions (set up the customer and the order), state the action (compute shipping), and assert the expected outcome (free shipping / 10% / standard).

The big win is not the speed — it is the defensibility. When a developer says "I do not understand why this row should be free shipping," you can both look at the same table and have a five-minute conversation. Without the table, that conversation is half an hour and one of you will be wrong.

When to use decision tables

Decision tables are the right tool when behaviour depends on 2–6 conditions combined together. Below 2 conditions, equivalence partitioning is enough. Above 6, the table grows to 64+ rows and pairwise testing becomes more practical (covered in the next lesson). Discount engines, eligibility rules, pricing calculators, fraud-scoring rules, and access-control checks are the classic use cases.

⚠️ Common mistakes

  • Skipping rows that "obviously" cannot happen. "A non-member with a £20 international order — nobody does that." Yes they do. Every row gets enumerated, every row gets tested.
  • Reducing the table before completing it. It is tempting to merge similar-looking rows, but the bugs hide in the differences. Fill in every cell first; collapse only after.
  • Treating the table as documentation, not a test contract. The point is not to record decisions — it is to derive test cases from them. Each row must end up as a test someone runs.

🎯 Practice task

Pick a feature where behaviour depends on multiple conditions — a discount engine, an eligibility check, a delivery cost calculator. Spend 25 minutes building a decision table.

  1. Identify 3 or 4 yes/no conditions that affect the outcome.
  2. Enumerate all 2ⁿ rows. With 3 conditions you will have 8 rows; with 4 you will have 16.
  3. Fill in the expected action for each row. If you find one you cannot answer, write it as a question for the PM rather than guessing.
  4. Reduce the table by collapsing don't-care conditions, marking each merged row with a for the irrelevant condition.
  5. Pick three of the rows — at least one happy path, one negative case, and one "edge" case — and write the full test case for each.

The next lesson tackles features where conditions are not yes/no but multi-valued, and the table would explode if you tried to fill it in completely.

// tip to track lessons you complete and pick up where you left off across devices.