Decision Tables and State Transition Testing
A decision table lists every rule your system enforces as a row, with the conditions that trigger it and the outcome it produces. A state transition test walks an entity through its lifecycle and checks that only the legal moves succeed. Both exist because the two most common test design techniques, equivalence partitioning and boundary value analysis, look at one input at a time, and a large share of real bugs only show up when two conditions or two states interact.
Decision tables: when rules combine
A discount field alone might need five test cases. A discount field that behaves differently for premium users, during a promotional window, in regions without local payment support, needs a table, because the outcome depends on which combination of conditions holds, not on any single input in isolation.
Build one by listing every condition as a row header, every combination as a column, and the expected outcome at the bottom of each column.
| Premium user | Promo active | Region supports local payment | Outcome |
|---|---|---|---|
| Yes | Yes | Yes | 20% off, local payment shown |
| Yes | Yes | No | 20% off, card only |
| Yes | No | Yes | 10% off, local payment shown |
| No | Yes | Yes | 15% off, local payment shown |
| No | No | No | No discount, card only |
Five columns instead of testing three binary conditions separately and hoping the combinations sort themselves out. With three yes/no conditions the full combination space is eight rows; most tables collapse some of those because certain combinations either can't happen or produce an identical outcome to another row. That collapsing is the actual skill in this technique: deciding which combinations matter enough to test explicitly.
Where it breaks down. Past four or five conditions, the combination count grows fast enough that a full table stops being practical. At that point, pairwise testing, which covers every pair of conditions rather than every combination, catches most of the same bugs with a fraction of the cases. Full decision tables belong on rule sets with a handful of conditions and real business consequences riding on getting the combination right, like pricing, permissions, or eligibility.
Free and open sourceCasely writes these cases for youAttach a spec and one file of your team's existing test cases in Claude. Casely copies your columns, names the gaps it found in the spec, and exports a single Excel file your tracker imports in one pass.Read the install docsState transition testing: when the bug is an illegal move
An entity with a lifecycle, a subscription, an order, a user account, moves through defined states. The bug that state transition testing catches isn't wrong behavior in one state. It's a transition that should have been blocked and wasn't.
Take a subscription moving through trial, active, past-due, and cancelled. Draw every state as a node and every legal transition as an arrow: trial to active on payment, active to past-due on a failed charge, past-due to active on a retried charge, active to cancelled on request, past-due to cancelled after a grace period expires.
The test cases that matter most aren't the arrows on the diagram. They're the arrows that don't exist. Can a cancelled subscription go directly back to active without going through a new trial or a fresh payment? Can a trial account skip straight to past-due without ever reaching active? If the state machine in the code doesn't block these, the entity ends up somewhere the business logic never accounted for, and the bug report that follows usually involves a customer who got something for free or got locked out of something they paid for.
Build the test set from three groups: every valid transition (confirm it works), every invalid transition reachable from each state (confirm it's blocked), and every state with no valid exit at all if the design calls for one (confirm the entity doesn't get stuck).
Where it breaks down. State transition testing assumes a defined, finite set of states with clear rules for moving between them. A feature that's really just a set of independent flags, not a lifecycle, doesn't have a real "current state" to violate, and the technique produces cases with no story behind them.
How do you tell them apart from equivalence partitioning and boundary value analysis?
Ask two questions about the feature under test. Does the outcome depend on more than one condition at once? That's a decision table question. Does the entity move through defined stages over time, where the current stage restricts what can happen next? That's a state transition question. If the answer to both is no, and you're testing a single input's valid range, you're back to equivalence partitioning and boundary value analysis, which is where testing usually starts before either of these two takes over.
Most real features need more than one of these four techniques stacked together. A subscription checkout has input ranges to partition, at least one pricing decision table, and a state machine for the subscription's lifecycle underneath all of it. Treating test design as picking one technique per feature undercounts what a feature this size actually needs.