Decision tables
In short: In a decision table every column is a combination of conditions with one result, and every column is a test case. Three conditions with "yes" or "no" give 8 columns. Columns with the same result that differ in only one condition merge with "—" (does not matter), and there are fewer tests. An empty or disputed cell is a question for the owner.
Problem
Three tests, a wrong price
You know the discount rule: the promo code gives 10 % and does not apply to sale products; loyal customers get 5 %, on sale products too; discounts do not add up, the larger one applies.
The tester writes three tests: a customer with a code (10 %), a loyal customer without a code (5 %), a customer with nothing (0 %). They pass.
After release a loyal customer enters a code for a product not on sale and gets 15 %. Every condition was tested. The combination where the bug lived was not.
The idea
Every column is a test
In the lesson "When a table is clearer" the decision table was a requirement. Now it is test design: every column is a test case.
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
|---|---|---|---|---|---|---|---|---|
| The code is valid | yes | yes | yes | yes | no | no | no | no |
| The product is on sale | yes | yes | no | no | yes | yes | no | no |
| The customer is loyal | yes | no | yes | no | yes | no | yes | no |
| Discount | ? | ? | ? | 10 % | ? | ? | 5 % | 0 % |
The tests from the start were columns 4, 7 and 8. The bug was in column 3. The coverage of the table is how many of the columns are tested: here 3 of 8.
The full table is easy to build: the conditions become rows, and the columns are all the combinations. Three conditions with "yes" or "no" give 2 × 2 × 2 = 8.
Try it
Columns as tests
Fill in the discount for each of the eight columns. Here the columns of the table are rows: every row is one test case.
The rule: A valid promo code gives 10%, but not on products on sale. A loyal customer gets 5%, on sale products too. Discounts do not add up: the larger one applies.
| Input | Expected | The correct system | ||||
|---|---|---|---|---|---|---|
| # | Valid code | On sale | Loyal | Discount | ||
Write the discount as a number: 10 or 10%. An empty result cell is not checked.
Solution
| Valid code | On sale | Loyal | Discount |
|---|---|---|---|
| yes | yes | yes | 5 |
| yes | yes | no | 0 |
| yes | no | yes | 10 |
| yes | no | no | 10 |
| no | yes | yes | 5 |
| no | yes | no | 0 |
| no | no | yes | 5 |
| no | no | no | 0 |
Column 3 (valid code, not on sale, loyal customer) catches two bugs: discounts added up (15 %) and the smaller one instead of the larger (5 %). Column 1 catches the code that switches off loyalty and gives 0 % on a product on sale. The full table misses nothing, because it tries every combination.
The idea
Collapsing
Look at columns 1 and 5. They differ only in the code, and the result is the same: 5 %. When the product is on sale and the customer is loyal, the code does not matter. The two columns merge into one, and "—" is written in place of the code.
| 1+5 | 2+6 | 3+4 | 7 | 8 | |
|---|---|---|---|---|---|
| The code is valid | — | — | yes | no | no |
| The product is on sale | yes | yes | no | no | no |
| The customer is loyal | yes | no | — | yes | no |
| Discount | 5 % | 0 % | 10 % | 5 % | 0 % |
Eight tests become five. This is collapsing the table.
Its cost: merging says "by the rule this condition does not matter". But the black box does not know whether the code agrees. Columns 3 and 4 merge into "code yes, sale no", and column 3 is exactly where the code gave 15 %. If from the merged column you test only a customer who is not loyal, the bug slips through.
A test cannot be "—": in place of the dash you pick a value. Pick the one where a bug is most likely. That is why for risky rules the full table is tested, and you collapse when tests are expensive and the risk is small.
More precisely, if you are curious
ISTQB CTFL v4.0.1 describes the technique in section 4.2.3 (decision table testing). Conditions and actions are rows, columns are the rules (the combinations). The notation: "T" and "F" for conditions, "—" for a condition that does not matter, "N/A" for an infeasible combination, "X" for an action that takes place. Coverage is the number of tested columns over all feasible ones. Collapsing (minimization) reduces the number of tests, but the syllabus notes that part of the checking is lost that way.
Try it
Merge the columns
Build the collapsed table: at most 5 rows that still catch every bug. Where the lesson has "—", pick a value.
The rule: A valid promo code gives 10%, but not on products on sale. A loyal customer gets 5%, on sale products too. Discounts do not add up: the larger one applies.
| Input | Expected | The correct system | ||||
|---|---|---|---|---|---|---|
| # | Valid code | On sale | Loyal | Discount | ||
Write the discount as a number: 10 or 10%. An empty result cell is not checked.
Solution
| Valid code | On sale | Loyal | Discount |
|---|---|---|---|
| yes | yes | yes | 5 |
| yes | yes | no | 0 |
| yes | no | yes | 10 |
| no | no | yes | 5 |
| no | no | no | 0 |
In 3+4 loyalty is "yes": that is where the discounts could add up. In 1+5 the code is "yes": that is where the code could apply to a product on sale or switch off loyalty. Five rows catch everything the eight catch, but only with these values. With "no" in place of every dash the table is still collapsed, and four bugs slip through.
The idea
More than two values
"The code is valid" looks like "yes" or "no". In the shop it is not. The code can be not entered, valid, expired or already used, and each gives the customer something different:
| 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|
| A code is entered | no | yes | yes | yes | yes |
| It has expired | N/A | no | yes | no | yes |
| It has been used | N/A | no | no | yes | yes |
| The customer sees | the total without a code | the discount | "The code has expired" | "The code has already been used" | ? |
Two things show at once.
Impossible combinations. A code that was not entered cannot have expired. Such columns are marked as impossible (N/A) and are not tested.
The empty cell. Column 5: the code has both expired and been used. Which message? The rule does not say. The tester does not decide for the owner. This is a finding, and it came out of the table before there was any code. That is why test design is also a review.
Columns grow fast: one condition with four values and two with two each give 4 × 2 × 2 = 16. With ten "yes or no" conditions it is 1024. Then the rule is split into smaller tables, and the combinations are chosen with another technique, such as pairwise testing later in the module.
Exercise
The tables of the code
1. What does the table say? Four questions the tester finds while writing the table.
Test
Check yourself
Related lessons
Section titled "Related lessons"- Builds on: Acceptance criteria · Reviewing a specification · Equivalence partitions · Boundary values
- Continues in: State transitions · Pairwise testing · Code coverage · Testing from experience
- Tasks on this topic: Test design techniques