Many systems behave differently depending on their current state. An online order can be Draft, Submitted, Approved, Shipped, Delivered, or Cancelled — and the actions available to the user change depending on which state the order is in. You can cancel a Draft order but not a Delivered one. You can approve a Submitted order but not a Shipped one. State transition testing models these states and the transitions between them to verify that the system allows valid transitions, blocks invalid ones, and updates its state correctly after each action.
State Transition Testing — Modelling Dynamic Behaviour
A state transition model has four components: states (the conditions the system can be in), events (triggers that cause transitions), transitions (the valid paths between states), and actions (what the system does during a transition). Test cases are designed to exercise every valid transition and attempt every invalid one.
# State Transition Model: Online Order Management
STATES = ["Draft", "Submitted", "Approved", "Shipped", "Delivered", "Cancelled"]
# Valid transitions: (from_state, event) → (to_state, action)
VALID_TRANSITIONS = [
("Draft", "Submit", "Submitted", "Send confirmation email"),
("Draft", "Cancel", "Cancelled", "No charge; remove from queue"),
("Submitted", "Approve", "Approved", "Charge payment; notify warehouse"),
("Submitted", "Reject", "Draft", "Send rejection reason to customer"),
("Submitted", "Cancel", "Cancelled", "Refund if charged; notify customer"),
("Approved", "Ship", "Shipped", "Update tracking; notify customer"),
("Approved", "Cancel", "Cancelled", "Full refund; notify warehouse"),
("Shipped", "Deliver", "Delivered", "Confirm delivery; close order"),
("Shipped", "Return", "Approved", "Process return; schedule pickup"),
]
# Invalid transitions — these should be BLOCKED by the system
INVALID_TRANSITIONS = [
("Delivered", "Cancel", "Cannot cancel a delivered order"),
("Delivered", "Ship", "Cannot re-ship a delivered order"),
("Cancelled", "Approve", "Cannot approve a cancelled order"),
("Cancelled", "Ship", "Cannot ship a cancelled order"),
("Draft", "Ship", "Cannot ship without approval"),
("Draft", "Deliver", "Cannot deliver a draft order"),
("Shipped", "Approve", "Already approved — cannot re-approve"),
]
print("State Transition Model — Order Management")
print("=" * 70)
print(f"\nStates: {', '.join(STATES)}")
print(f"\nValid Transitions ({len(VALID_TRANSITIONS)}):")
print(f"{'From':<12} {'Event':<10} {'To':<12} {'Action'}")
print("-" * 70)
for from_s, event, to_s, action in VALID_TRANSITIONS:
print(f"{from_s:<12} {event:<10} {to_s:<12} {action}")
print(f"\nInvalid Transitions to TEST ({len(INVALID_TRANSITIONS)}):")
print(f"{'From':<12} {'Event':<10} {'Expected Behaviour'}")
print("-" * 70)
for from_s, event, reason in INVALID_TRANSITIONS:
print(f"{from_s:<12} {event:<10} BLOCKED — {reason}")
# Derive test cases
print(f"\n\nTest Case Summary:")
print(f" Valid transition tests: {len(VALID_TRANSITIONS)} (verify state changes correctly)")
print(f" Invalid transition tests: {len(INVALID_TRANSITIONS)} (verify system blocks them)")
print(f" Total: {len(VALID_TRANSITIONS) + len(INVALID_TRANSITIONS)} test cases")
# Sequence testing — multi-step paths through states
print(f"\n Example valid path: Draft → Submit → Approve → Ship → Deliver")
print(f" Example cancel path: Submitted → Cancel (refund issued)")
print(f" Example reject path: Submitted → Reject → Draft (re-edit)")
Common Mistakes
Mistake 1 — Only testing the happy path through the state machine
❌ Wrong: Testing only Draft → Submit → Approve → Ship → Deliver and declaring state transition testing complete.
✅ Correct: Testing every valid transition individually, every invalid transition (attempting to perform actions that should be blocked), and key multi-step sequences including cancellations, rejections, and retries.
Mistake 2 — Not verifying that the system's state actually changes
❌ Wrong: Clicking "Submit" and seeing a success message, then assuming the order is in the "Submitted" state without verifying.
✅ Correct: After each transition, verifying the new state by checking the order status display, the available actions (Cancel should be available; Ship should not), and the database or API response that confirms the state change.