Learning Objectives
By the end of this lesson you will be able to:
- Build a state transition table from a state diagram
- Identify all invalid transitions in the table
- Write test cases targeting invalid transitions
The State Transition Table
A state diagram is visual and intuitive — great for communication. But for test design, a state transition table is more rigorous. It's a matrix where:
- Rows = current states
- Columns = events
- Cells = next state (if valid) or "–" / "Error" (if invalid)
Building the Table
From our task management example:
| Current State | Start Work | Submit for Review | Approve | Request Changes | Cancel |
|---|---|---|---|---|---|
| Draft | In Progress | – | – | – | Cancelled |
| In Progress | – | In Review | – | – | Cancelled |
| In Review | – | – | Done | In Progress | Cancelled |
| Done | – | – | – | – | – |
| Cancelled | – | – | – | – | – |
The "–" cells are the gold: these are the invalid transitions. There are 14 invalid combinations in this table. Most test suites test 0 of them.
Why Invalid Transitions Are Critical
"It will never happen in practice" is not a defense. Users click back buttons. Data gets imported from external systems. APIs are called in unexpected orders. Scripts are run by developers against the database. Invalid state transitions happen — and when they do, the system either:
- Rejects gracefully with a clear error
- Silently ignores the event (and data becomes inconsistent)
- Crashes
Only the first is acceptable. The other two are bugs that state transition testing catches.
Test Cases for Invalid Transitions
For each "–" cell, write a test case that attempts the invalid transition and verifies the correct response:
- TC-001: Task in state
Done+ "Cancel" event → Expect: error or rejection, task remainsDone - TC-002: Task in state
Draft+ "Approve" event → Expect: error or rejection, task remainsDraft - TC-003: Task in state
Cancelled+ "Start Work" event → Expect: error or rejection, task remainsCancelled
Pro Tip: Invalid transitions often reveal the "feature/bug" category: behavior that was never specified but affects real users. When you find that
Cancelled → Start Workis silently accepted, that's a conversation to have with the product team — is it a bug or a feature?
Combining with Guard Testing
When a transition has a guard condition (e.g., "Cancel is only allowed if status != Shipped"), add test cases for both sides of the guard:
- Guard passes: cancel a non-shipped order → should succeed
- Guard fails: cancel a shipped order → should be blocked
This is not just an invalid transition — it's a conditional transition, and both the true and false guard paths need separate tests.
All-Pairs on State Transitions
For systems with many states and events, testing every invalid transition is expensive. Apply the pairwise principle (Module 5): select a subset of invalid transitions that covers every (state × invalid event) pair at least once.
Summary
The state transition table converts a visual state diagram into a structured test design artifact. Every "–" cell is a test case waiting to be written. Testing invalid transitions — the ones nobody thinks to test — is the highest-value practice in state transition testing, because that's where the assumption "this can never happen" meets the reality "this just happened in production."