Skip to content

Decision table exercises with answers (ISTQB style)

Ten business rules with three or four conditions, in the style of ISTQB decision-table exercises. For each, build the full decision table, mark the rows on which the action is taken, and collapse the table by merging combinations that differ in a condition that does not affect the action, counting the rules that remain. The truth table under each problem is the full table, action column included.

A full decision table lists every combination of the conditions, 8 rows for three and 16 for four, with the action per row; it is the truth table of the rule, with the conditions as inputs and the action as the output, and the engine's table under the problem is exactly that. Rows are numbered with the first condition as the most significant bit, in the order the conditions appear in the rule; the solutions give the action rows as assignments and as row numbers in that order.

Collapsing replaces two rows that differ only in one condition and agree in the action by one rule with a dash for that condition. Collapse one condition at a time and check that every original row is still covered exactly once. The solutions give one collapsed table per rule; another grouping with the same number of rules is just as valid, and the test that matters is that the collapsed rules reproduce the action column row for row.

1. Free shipping applies to orders over 50 or to Prime members, but not to oversized items. Conditions over_50, prime, oversized. Build the decision table, list the rows that ship free, and collapse it. (over_50 OR prime) AND NOT oversized
#over_50primeoversizedf
0FALSEFALSEFALSEFALSE
1FALSEFALSETRUEFALSE
2FALSETRUEFALSETRUE
3FALSETRUETRUEFALSE
4TRUEFALSEFALSETRUE
5TRUEFALSETRUEFALSE
6TRUETRUEFALSETRUE
7TRUETRUETRUEFALSE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

(over_50 OR prime) AND NOT oversized

Classification: contingent

Three rows ship free, all with oversized = FALSE: over_50 = FALSE, prime = TRUE (row 2), over_50 = TRUE, prime = FALSE (row 4) and over_50 = TRUE, prime = TRUE (row 6). Collapsed to four rules: oversized → no; not oversized and over 50 (Prime: dash) → yes; not oversized, not over 50, Prime → yes; not oversized, not over 50, not Prime → no.

2. A discount applies to students and seniors whose card has not expired. Conditions student, senior, expired. Build the table, list the discount rows and collapse it. (student OR senior) AND NOT expired
#studentseniorexpiredf
0FALSEFALSEFALSEFALSE
1FALSEFALSETRUEFALSE
2FALSETRUEFALSETRUE
3FALSETRUETRUEFALSE
4TRUEFALSEFALSETRUE
5TRUEFALSETRUEFALSE
6TRUETRUEFALSETRUE
7TRUETRUETRUEFALSE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

(student OR senior) AND NOT expired

Classification: contingent

Discount on student = FALSE, senior = TRUE, expired = FALSE (row 2), student = TRUE, senior = FALSE, expired = FALSE (row 4) and student = TRUE, senior = TRUE, expired = FALSE (row 6). Collapsed to four rules: expired → no; not expired and student (senior: dash) → yes; not expired, not student, senior → yes; not expired, neither → no.

3. A loan is granted when income is sufficient, the applicant has a good credit record or a guarantor, and is not bankrupt. Conditions income_ok, credit_ok, guarantor, bankrupt. Build the 16-row table, list the granting rows and collapse it. income_ok AND (credit_ok OR guarantor) AND NOT bankrupt
#income_okcredit_okguarantorbankruptf
0FALSEFALSEFALSEFALSEFALSE
1FALSEFALSEFALSETRUEFALSE
2FALSEFALSETRUEFALSEFALSE
3FALSEFALSETRUETRUEFALSE
4FALSETRUEFALSEFALSEFALSE
5FALSETRUEFALSETRUEFALSE
6FALSETRUETRUEFALSEFALSE
7FALSETRUETRUETRUEFALSE
8TRUEFALSEFALSEFALSEFALSE
9TRUEFALSEFALSETRUEFALSE
10TRUEFALSETRUEFALSETRUE
11TRUEFALSETRUETRUEFALSE
12TRUETRUEFALSEFALSETRUE
13TRUETRUEFALSETRUEFALSE
14TRUETRUETRUEFALSETRUE
15TRUETRUETRUETRUEFALSE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

income_ok AND (credit_ok OR guarantor) AND NOT bankrupt

Classification: contingent

Three of sixteen rows grant the loan, all with income_ok = TRUE, bankrupt = FALSE: credit_ok = FALSE, guarantor = TRUE (row 10), credit_ok = TRUE, guarantor = FALSE (row 12) and credit_ok = TRUE, guarantor = TRUE (row 14). Collapsed to five rules: income not ok → no; bankrupt → no; income ok, not bankrupt, credit ok (guarantor: dash) → yes; income ok, not bankrupt, no credit, guarantor → yes; income ok, not bankrupt, no credit, no guarantor → no.

4. The alarm sounds when the system is armed and a door or a window is open. Conditions armed, door, window. Build the table, list the alarm rows and collapse it. armed AND (door OR window)
#armeddoorwindowf
0FALSEFALSEFALSEFALSE
1FALSEFALSETRUEFALSE
2FALSETRUEFALSEFALSE
3FALSETRUETRUEFALSE
4TRUEFALSEFALSEFALSE
5TRUEFALSETRUETRUE
6TRUETRUEFALSETRUE
7TRUETRUETRUETRUE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

armed AND (door OR window)

Classification: contingent

Alarm on armed = TRUE with door = FALSE, window = TRUE (row 5), door = TRUE, window = FALSE (row 6) and door = TRUE, window = TRUE (row 7). Collapsed to four rules: not armed → no; armed and door open (window: dash) → yes; armed, door closed, window open → yes; armed, both closed → no.

5. A visitor is admitted with a passport, or with an ID card if of age. Conditions passport, age_ok, id_card. Build the table, list the admitted rows and collapse it. passport OR (age_ok AND id_card)
#passportage_okid_cardf
0FALSEFALSEFALSEFALSE
1FALSEFALSETRUEFALSE
2FALSETRUEFALSEFALSE
3FALSETRUETRUETRUE
4TRUEFALSEFALSETRUE
5TRUEFALSETRUETRUE
6TRUETRUEFALSETRUE
7TRUETRUETRUETRUE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

passport OR (age_ok AND id_card)

Classification: contingent

Five rows admit: the four with passport = TRUE (rows 4 to 7) and passport = FALSE, age_ok = TRUE, id_card = TRUE (row 3). Collapsed to four rules: passport (others: dash) → yes; no passport, of age, ID card → yes; no passport, not of age → no; no passport, of age, no ID card → no.

6. A record may be edited by a logged-in user whose account is not locked and who is its owner or an admin. Conditions logged_in, locked, owner, admin. Build the 16-row table, list the editing rows and collapse it. logged_in AND NOT locked AND (owner OR admin)
#logged_inlockedowneradminf
0FALSEFALSEFALSEFALSEFALSE
1FALSEFALSEFALSETRUEFALSE
2FALSEFALSETRUEFALSEFALSE
3FALSEFALSETRUETRUEFALSE
4FALSETRUEFALSEFALSEFALSE
5FALSETRUEFALSETRUEFALSE
6FALSETRUETRUEFALSEFALSE
7FALSETRUETRUETRUEFALSE
8TRUEFALSEFALSEFALSEFALSE
9TRUEFALSEFALSETRUETRUE
10TRUEFALSETRUEFALSETRUE
11TRUEFALSETRUETRUETRUE
12TRUETRUEFALSEFALSEFALSE
13TRUETRUEFALSETRUEFALSE
14TRUETRUETRUEFALSEFALSE
15TRUETRUETRUETRUEFALSE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

logged_in AND NOT locked AND (owner OR admin)

Classification: contingent

Three rows allow editing, all with logged_in = TRUE, locked = FALSE: owner = FALSE, admin = TRUE (row 9), owner = TRUE, admin = FALSE (row 10) and owner = TRUE, admin = TRUE (row 11). Collapsed to five rules: not logged in → no; logged in but locked → no; logged in, not locked, owner (admin: dash) → yes; logged in, not locked, not owner, admin → yes; logged in, not locked, neither → no.

7. A year is a leap year when it is divisible by 4, except years divisible by 100, unless also divisible by 400. Conditions divisible_by_4, divisible_by_100, divisible_by_400. Build the table, list the leap rows and collapse it. divisible_by_4 AND (NOT divisible_by_100 OR divisible_by_400)
#divisible_by_4divisible_by_100divisible_by_400f
0FALSEFALSEFALSEFALSE
1FALSEFALSETRUEFALSE
2FALSETRUEFALSEFALSE
3FALSETRUETRUEFALSE
4TRUEFALSEFALSETRUE
5TRUEFALSETRUETRUE
6TRUETRUEFALSEFALSE
7TRUETRUETRUETRUE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

divisible_by_4 AND (NOT divisible_by_100 OR divisible_by_400)

Classification: contingent

Leap on divisible_by_4 = TRUE with divisible_by_100 = FALSE, divisible_by_400 = FALSE (row 4), with divisible_by_100 = FALSE, divisible_by_400 = TRUE (row 5, infeasible in reality) and with both TRUE (row 7). Collapsed to four rules: not divisible by 4 → no; divisible by 4, not by 100 (400: dash) → yes; by 4, by 100 and by 400 → yes; by 4 and by 100, not by 400 → no.

8. A confirmed order is accepted when it is paid by exactly one method, cash or card. Conditions confirmed, cash, card. Build the table, list the accepted rows and collapse it. confirmed AND (cash XOR card)
#confirmedcashcardf
0FALSEFALSEFALSEFALSE
1FALSEFALSETRUEFALSE
2FALSETRUEFALSEFALSE
3FALSETRUETRUEFALSE
4TRUEFALSEFALSEFALSE
5TRUEFALSETRUETRUE
6TRUETRUEFALSETRUE
7TRUETRUETRUEFALSE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

confirmed AND (cash XOR card)

Classification: contingent

Two rows accept: confirmed = TRUE, cash = FALSE, card = TRUE (row 5) and confirmed = TRUE, cash = TRUE, card = FALSE (row 6). Collapsed to five rules: not confirmed → no; confirmed, cash only → yes; confirmed, card only → yes; confirmed, both → no; confirmed, neither → no. The XOR does not collapse further, because the two accepting rows differ in two conditions.

9. A customer receives a coupon if they are VIP, or if they have placed three orders and never returned one. Conditions vip, orders_3, returned. Build the table, list the coupon rows and collapse it. vip OR (orders_3 AND NOT returned)
#viporders_3returnedf
0FALSEFALSEFALSEFALSE
1FALSEFALSETRUEFALSE
2FALSETRUEFALSETRUE
3FALSETRUETRUEFALSE
4TRUEFALSEFALSETRUE
5TRUEFALSETRUETRUE
6TRUETRUEFALSETRUE
7TRUETRUETRUETRUE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

vip OR (orders_3 AND NOT returned)

Classification: contingent

Five rows give a coupon: the four with vip = TRUE (rows 4 to 7) and vip = FALSE, orders_3 = TRUE, returned = FALSE (row 2). Collapsed to four rules: VIP (others: dash) → yes; not VIP, three orders, no return → yes; not VIP, fewer than three orders → no; not VIP, three orders, a return → no.

10. A machine runs when start is pressed, the guard is closed, and neither the emergency stop nor a fault is active. Conditions start, guard_closed, estop, fault. Build the 16-row table, list the running rows and collapse it. start AND guard_closed AND NOT (estop OR fault)
#startguard_closedestopfaultf
0FALSEFALSEFALSEFALSEFALSE
1FALSEFALSEFALSETRUEFALSE
2FALSEFALSETRUEFALSEFALSE
3FALSEFALSETRUETRUEFALSE
4FALSETRUEFALSEFALSEFALSE
5FALSETRUEFALSETRUEFALSE
6FALSETRUETRUEFALSEFALSE
7FALSETRUETRUETRUEFALSE
8TRUEFALSEFALSEFALSEFALSE
9TRUEFALSEFALSETRUEFALSE
10TRUEFALSETRUEFALSEFALSE
11TRUEFALSETRUETRUEFALSE
12TRUETRUEFALSEFALSETRUE
13TRUETRUEFALSETRUEFALSE
14TRUETRUETRUEFALSEFALSE
15TRUETRUETRUETRUEFALSE

The engine found no law that shortens this expression; it is already as short as its rewriting laws can make it.

start AND guard_closed AND NOT (estop OR fault)

Classification: contingent

A single row runs: start = TRUE, guard_closed = TRUE, estop = FALSE, fault = FALSE (row 12). Collapsed to five rules: no start → no; start, guard open → no; start, guard closed, estop → no; start, guard closed, no estop, fault → no; all four conditions as required → yes. Each blocking condition collapses the rows after it, so the five rules cover the sixteen combinations.

Questions

Which combinations are infeasible, and what do I do with them?

Some combinations cannot occur: a year divisible by 400 is always divisible by 100, so divisible_by_100 = FALSE, divisible_by_400 = TRUE never happens. The full table still lists the row, and the engine computes the rule on it; in a test design you mark it infeasible rather than writing a test for it, and you say so in the table.

Related

Compare

See also

Practice

Generated from the Tangibool engine, semantics tangibool-semantics/1, engine 1.0.0, build . Every table, map, simplification and verdict on these pages was computed by the Tangibool engine when the site was built, and every claim was re-checked by the same exact checker the app uses. Limits are stated where they apply. © 2026 Foreranger LTD.