What do blank cells in a state transition table mean, and how do you test them?
answer
- The grid shows what was never drawn
- Rejected, ignored, or simply undecided
- Assert unchanged state and no side effect
- The arrow the code has and the model lacks
- A target column with no entries means unreachable
basics
~20 sA blank cell is a state-event pair the specification never defined. Test it by driving the system into that state, firing that event, and checking the system rejects or ignores it safely instead of quietly moving somewhere the model never drew.
solid answer
~50 sA state transition table puts states down the rows and events across the columns, so every cell is one state-event pair. Filled cells hold specified transitions; **blank cells are combinations the specification never addressed**, and they are the negative test material. Distinguish three outcomes before you write assertions: *rejected* — the event is refused with an error and the state is unchanged; *ignored* — the event is silently absorbed, still no state change; and *undefined* — nobody decided, which is a specification defect to raise rather than a behaviour to codify. Test a blank cell by reaching the state, firing the event, then asserting the state is unchanged **and** no side effect happened. What you are hunting is a **sneak path**: a transition the implementation actually has and the model never drew. Those are invisible to any amount of positive transition coverage.
code
pseudocode · 13 linesstate / event | reserve | amend | cancel | pick | ship
--------------+----------+----------+-----------+---------+--------
Draft | Reserved | Draft | Cancelled | . | .
Reserved | . | Reserved | Cancelled | Picked | .
Picked | . | . | Cancelled | . | Shipped
Shipped | . | . | . | . | .
TEST blank_cell:
given row IS Picked
when fire reserve
then row IS Picked # state unchanged
and holdCount UNCHANGED # the assertion that finds the sneak path
and response IS rejectiongo deeper
Know that a state transition table has one cell per state-event pair, that empty cells are the combinations nobody specified, and that testing one means firing the event and checking nothing moved.
Be able to separate rejected, ignored and genuinely undefined cells, and to say what each one asserts. Explain what a sneak path is and why positive transition coverage cannot find one.
Show how you prioritise thirty-plus negative cells: resource-touching events, realistically reachable sequences, post-terminal duplicates. Be ready to describe a defect that hid behind an unchanged state field.
Own the policy on undefined cells — that silence in a requirement is a defect to raise, not a behaviour to invent — and decide how much negative state testing a feature's risk profile actually buys.
### The table form and why it exposes gaps A state transition diagram shows what the system *does*. A state transition table shows the same information as a grid — states as rows, events as columns — and its value is that it also shows what the system does *not* do, as empty cells. A warehouse stock ledger with six states (Draft, Reserved, Picked, Shipped, Cancelled, Expired) and seven events (reserve, amend, cancel, expire, pick, ship, split) yields a grid of forty-two cells. If ten arrows were specified, thirty-two cells are blank. The diagram makes those thirty-two invisible; the table makes them a checklist. ### Three different meanings of an empty cell The word "blank" hides a distinction that matters for what you assert: - **Rejected (invalid event).** The specification says this event is not allowed here and the system must refuse it — an error response, a rejection code, an audit entry — with no state change. - **Ignored.** The specification says the event is absorbed with no effect and no complaint. Common for idempotent or duplicated messages: firing cancel on an already-cancelled row is a no-op, not an error. - **Undefined.** Nobody decided. The cell is blank because the requirement is silent, not because silence was chosen. This is a specification defect. Raising it is part of the tester's job and is usually worth more than the test case you would otherwise write. The distinction between rejected and ignored is a real interview trap, because both leave the state unchanged and both look identical if your only assertion is on the state. Only the response and the side effects tell them apart, so decide which the requirement wants before writing the assertion. ### Sneak paths A **sneak path** is a transition the implementation has and the model does not. Nothing in positive transition coverage can find one: every arrow you drew passes, and the extra arrow is by definition not drawn. The only way in is through the blank cells — reach the state, fire the event, and see whether anything moves. A concrete shape it takes: in that ledger, the cell for state Picked and event reserve was blank, and nobody had discussed it. The implementation accepted it, placed a *second* stock hold, and left the first one in place, since the release only ran on the Reserved-to-Cancelled arrow. An overnight retry loop drove that cell 2,148 times and exhausted the ledger's pool of hold rows, at which point no new reservation anywhere in the warehouse could be created — a resource exhaustion whose root cause was one untested blank cell. The team of eleven had full 0-switch coverage and a green suite throughout. ### Unreachable states and dead arrows The table also shows the opposite gap. Read a column of targets: if a state never appears as any transition's target, it is **unreachable** — either an arrow is missing from the model or the state is dead and should be deleted. If a state has no outgoing arrows and is not meant to be terminal, it is a trap state, and something that entered it can never leave. Both are model review findings you get for free from the tabular form, before a single test runs. ### How many blank cells to test Thirty-two negative cases is often more than the feature is worth, so prioritise rather than pretending you will do them all: - Cells whose event **allocates or releases a resource** — those are the ones with a failure mode worse than a wrong error message. - Cells reachable by a **realistic** sequence: a retry, a duplicate message, a stale client, a double-click. Cells only reachable by an internal call nobody can make from outside score lower. - Cells around **terminal states**, since post-terminal events are what duplicated and replayed messages produce. - Cells where the requirement is **silent** — write the question up rather than guessing an assertion. ### What to assert For a rejected cell: the specified error is returned, the state is unchanged, and no side effect fired. For an ignored cell: no error, state unchanged, no side effect, and repeating the event stays harmless. In both cases the *no side effect* half is what catches the sneak path, because a sneak path very often leaves the state field alone while quietly doing something underneath — exactly the shape of the hold-leak above. Asserting only the visible state is how a suite stays green while the defect ships.
- How do you tell a rejected event from an ignored one when both leave the state unchanged?By the response and the side effects, never by the state. A rejected event returns an error or rejection code and usually writes an audit entry; an ignored event returns success and writes nothing. Decide which the requirement intends before you write the test, because asserting the wrong one bakes a guess into the suite. If the requirement does not say, that is the finding — raise it rather than picking one.
- Why can 1-switch coverage still miss a sneak path?Because switch coverage only walks arrows that exist in the model, and a sneak path is by definition an arrow the model does not have. Raising N buys longer legal sequences, not illegal ones. Sneak paths are found by deliberately firing events in states where the table has no entry, which is a different exercise from any level of positive transition coverage.
- What does it mean when a state never appears as a transition target in the table?It is unreachable. Either the model is missing an inbound arrow — a review finding against the model — or the state genuinely cannot occur and should be deleted from both the model and the code. Either way it is worth raising before test design, because writing cases that reach an unreachable state wastes effort and usually produces a back-door setup that proves nothing.
saying these in an interview costs you the question
- Treating every blank cell as simply forbidden
- Asserting the state only, never the side effects
- Confusing an ignored event with a rejected one
- Believing transition coverage would catch a sneak path
- Codifying undefined behaviour instead of raising it
- Trying to test all blank cells with no prioritisation