State Transition Testing

A RecipeBox recipe isn't just a static blob of data — it moves through distinct states over its lifetime. When you first create it, it's a Draft. Once you're happy with it and hit Publish, it becomes Published and visible to other users. If it's no longer relevant, you can move it to Archived. Each of these states allows different actions and a different set of "next possible states." State Transition Testing is the technique for verifying that a system behaves correctly as it moves between defined states — and just as importantly, that it correctly refuses to make transitions that shouldn't be allowed.

What Is State Transition Testing?

Any system with state transition testing needs three things clearly defined:

  • States — the distinct "modes" the object can be in (Draft, Published, Archived).
  • Events / actions — the things that trigger a move from one state to another (clicking Publish, clicking Archive, clicking Unpublish, clicking Restore to Draft).
  • Transitions — the specific state-to-state moves that a given event is allowed to cause. Not every event is valid from every state.

Testing this properly means checking every valid transition actually works, and — this is the part beginners skip — checking that every invalid transition is correctly blocked.

Worked Example: RecipeBox Recipe States

RecipeBox recipes support four transitions between three states:

From StateEvent / ActionTo State
DraftClick "Publish" (requires title + 1 ingredient + 1 step — see the Decision Table lesson)Published
PublishedClick "Unpublish"Draft
PublishedClick "Archive"Archived
ArchivedClick "Restore to Draft"Draft

As a simple text diagram, the valid flow looks like this:

  [Draft] --Publish--> [Published] --Archive--> [Archived]
     ^                       |                        |
     |                       +------Unpublish----------+ (back to Draft)
     +-----------------Restore to Draft----------------+
          

Every arrow in that diagram is one test case: start in the "from" state, trigger the event, and verify the recipe actually ends up in the "to" state (and that any side effects are correct too — e.g. an archived recipe should disappear from the main Recipe List and Search results, while a published one should appear there).

Just as Important: Testing Invalid Transitions

A state machine is only as trustworthy as its ability to say "no" to a move that isn't allowed. For RecipeBox, these transitions should all be blocked:

Attempted TransitionExpected ResultWhy This Matters
Archived → Published (directly)Blocked — no "Publish" action should be available on an archived recipe; it must go back to Draft firstWithout this check, a recipe could skip the review implied by "creating a fresh draft" and go straight back live from an archived, possibly stale, state
Draft → Archived (directly, skipping Published)Blocked — Archiving only makes sense for something that was actually liveIf this succeeds, "Archived" loses its meaning as "was published, now retired" — reporting and history become unreliable
Published → Published (re-publish while already published)Should be a no-op or disabled control, not a duplicate transition or errorConfirms the UI doesn't offer, or the backend doesn't silently accept, an action that doesn't apply to the current state

These "should never happen" transitions matter more than they might seem: a UI bug (say, a stale "Publish" button still rendering on an archived recipe's screen after a background refresh) or an API called directly with the wrong recipe ID can trigger exactly these invalid moves in production, even though a normal user clicking around the UI in the expected order never would.

How to Approach State Transition Testing

  1. Draw the state diagram first. List every state, then every event, then which state each event leads to from each starting state.
  2. Write one test case per valid arrow in the diagram — set up the "from" state, trigger the event, confirm the "to" state and any related UI/data changes.
  3. List every combination of (state, event) that is NOT a valid arrow, and write a test case confirming each one is blocked or unavailable.
  4. Check what happens at the edges of a sequence — e.g., can you Archive a recipe twice in a row by double-clicking quickly? Can you Unpublish something that's already back in Draft?
Note: State transition testing pairs naturally with Decision Table Testing — the Draft → Published transition in RecipeBox is guarded by the exact decision table conditions from the previous lesson (title / ingredient / step). The state diagram tells you which transitions exist; the decision table tells you the detailed rule for when one specific transition is allowed to fire.
Up next: You've now learned four core design techniques. The next lesson, Writing Effective Test Cases, shows you how to turn any of these into a properly documented test case using the standard template testers use on the job.