State Transition Testing

State transition testing is a black-box test design technique for behaviour that depends on history. You model the system, or one thing it manages such as an account, an order or a document, as states and the events that move it between them, then derive test cases from that model. In sign-in with a one-time code, the account is Signed out, Code sent, Signed in or Locked: a wrong code keeps the user at Code sent the first two times and locks the account the third time. The same input gives a different result because the state is different.

Equivalence partitioning grouped input values that the system should treat alike. A state model does the same for histories: instead of trying every order of clicks, you test the few states the system can be in, the allowed moves between them, and the refusal of forbidden moves.

Why it matters

Many serious defects appear only after a particular history: a cancelled order that still ships, a locked account that accepts the correct code, a session that survives sign-out. Each input is valid on its own, so techniques that examine one input at a time miss them.

A state model turns a workflow into a finite list of coverage items, states and transitions, so you can say exactly what was tested. Building it also exposes gaps early: every combination of state and event that nobody specified becomes a question for the product owner, not a failure in production.

States, events, transitions and guards

A state is a condition the modelled object stays in until something happens. An event is what happens: a click, an incoming message, a timer running out. A transition is the change of state that an event causes; ISTQB treats it as instantaneous. It may cause an action, such as sending an SMS, and may carry a guard condition that must be true for the transition to fire.

Transitions are labelled event [guard] / action, leaving out parts that do not exist. Guards matter when one event can lead to different states: "wrong code [1st or 2nd wrong attempt]" keeps the user at Code sent, while "wrong code [3rd wrong attempt]" locks the account. A guard such as an attempt count is a boundary, so test both sides of it. The examples use this requirement:

  • The user requests a code; the system sends a 6-digit code by SMS, valid for 5 minutes.
  • The correct code signs the user in, and a code works only once. Signing out ends the session.
  • After a wrong code the user may try again; the third wrong code in a row locks the account for 30 minutes, after which the user can request a new code.

The state diagram and the state table

A state diagram, also called a state transition diagram, draws states as boxes and valid transitions as labelled arrows. For the sign-in requirement it has four states, S1 to S4, and seven transitions, T1 to T7. It is easy to review with the team, but it shows only what is allowed.

One-time-code sign-in as a state diagram: 4 states and 7 valid transitions, where a guard on the wrong-attempt count decides whether a wrong code keeps the user at Code sent or locks the account.
Transitions
#FromToEvent [guard] / action
1S1 Signed outStartS2 Code sentE1 request code / send a 6-digit code by SMS
2S2 Code sentS3 Signed inE2 correct code / open a session
3S2 Code sentS2 Code sentE3 wrong code [1st or 2nd wrong attempt] / show the attempts leftalternative path
4S2 Code sentS4 LockedE3 wrong code [3rd wrong attempt in a row]alternative path
5S2 Code sentS1 Signed outStartE4 code expires (5 minutes after sending)alternative path
6S3 Signed inS1 Signed outStartE5 sign out / end the session
7S4 LockedS1 Signed outStartE6 lock ends (30 minutes later)alternative path

Only valid transitions are drawn. The state table below shows the other state and event pairs: the invalid transitions, and one gap the requirement leaves open.

A state table holds the same model as a grid: one row per state, one column per event, and in each cell the transition and its target state. It also shows what is forbidden: an empty cell, a dash below, is an invalid transition, where the system should refuse or ignore the event and stay in its state. The ISTQB syllabus gives each event and guard pair its own column, so E3 would take two; this table keeps both guards of E3 in one cell to stay narrow.

Filling the table reveals gaps. The requirement does not say what happens if the user requests another code while the first is still valid, so the cell S2 × E1 holds a question for the product owner, not a test.

                 E1        E2        E3                E4        E5        E6
                 request   correct   wrong             code      sign      lock
                 code      code      code              expires   out       ends
S1 Signed out    T1: S2    -         -                 -         -         -
S2 Code sent     ?         T2: S3    T3: S2 [1st,2nd]  T5: S1    -         -
                                     T4: S4 [3rd]
S3 Signed in     -         -         -                 -         T6: S1    -
S4 Locked        -         -         -                 -         -         T7: S1

-  invalid transition: refused, the state does not change
?  not specified in the requirement: ask the product owner

Try it: State Transition Generator

Coverage: all states, valid transitions, all transitions

A test case here is a sequence of events from a known start state, with the expected state and action after each event; one test case usually covers several transitions. The ISTQB Foundation syllabus discusses three coverage criteria. Each is stronger than the one before it: 100% of a later criterion guarantees 100% of the earlier ones.

  • All states coverage: the coverage items are the states. Two test cases reach 100%, E1, E2 and E1, E3, E3, E3, yet they exercise only T1 to T4: 4 of 7 valid transitions (57%). Code expiry, sign-out and the end of the lock stay untested.
  • Valid transitions coverage, also called 0-switch coverage: the coverage items are the single valid transitions, T1 to T7. It is the most widely used criterion, and reaching 100% also exercises every state.
  • All transitions coverage: the coverage items are all transitions in the state table; every valid one is exercised and every invalid one attempted. The syllabus recommends it as a minimum for mission- and safety-critical software.

Worked example: test cases for the one-time code

For valid transitions coverage, start each test case in S1 and chain events until every transition has been exercised. Three test cases are enough. One long sequence could cover all seven, because T5, T6 and T7 all return to S1, but then a failure early in the sequence blocks every transition after it. In TC-03 the first two wrong codes exercise T3, because the guard is true, and the third exercises T4.

Write each expected result as the state and the action, not only the screen message: after the second wrong code the user is still at S2 and sees that one attempt is left. TC-02 and TC-03 wait 5 and 30 minutes, so ask early whether the test environment can shorten these times or set the clock.

Every test case starts in S1 Signed out.

ID     Events and resulting states                            Covers
TC-01  E1 -> S2   E2 -> S3   E5 -> S1                         T1 T2 T6
TC-02  E1 -> S2   E4 -> S1                                    T1 T5
TC-03  E1 -> S2   E3 -> S2   E3 -> S2   E3 -> S4   E6 -> S1   T1 T3 T4 T7

Valid transitions coverage: 7 of 7 (100%)
All states coverage:        4 of 4 (100%)

Try it: Test Case Generator

Testing invalid transitions

Of the 17 empty cells in this table, five cannot be triggered: a lock can end only in S4, and an unused code, the only kind that can expire, exists only in S2 and S4. Mark these five as not testable and say why; the other 12 are the invalid transitions to attempt for all transitions coverage.

Attempt one per test case: if a first attempt is wrongly accepted, the system is no longer in the state the next attempt assumes, and one defect hides another (ISTQB calls this defect masking, also known as fault masking). The expected result is that the event is refused and the state does not change; confirm the state with the next event or through the API. Start with the attempts that matter most for security:

  • S4 × E2: while locked, enter the correct code before it expires. Expected: still Locked, no session.
  • S3 × E2: after signing in, submit the same code again. Expected: refused, one session only.
  • S1 × E2: enter a code after it has expired (T5). Expected: refused, still Signed out.
  • S4 × E1: request a new code while locked. Expected: no SMS is sent, still Locked.
  • S4 × E4: wait for the code to expire while the account is locked. Expected: still Locked; a move to Signed out would let the user request a new code long before the 30 minutes end.

Common mistakes

  • Modelling only the happy path and forgetting timeouts, cancellations, expiry and the way out of error states such as Locked.
  • Taking 100% all states coverage as enough: in the sign-in model, the two test cases that reach it leave three of the seven transitions untested.
  • Never attempting the events a state must refuse, or attempting several in one test case, so the first wrong result hides the others (defect masking).
  • Testing a guarded transition on one side of its guard only: the first wrong attempt, but never the third.
  • Checking the message instead of the state: a "request refused" message while the order still moves to Shipped is a failure.

The QA perspective

State transition testing starts in test analysis: words such as status, "after", "until", "only when" and "no longer" in a requirement signal a state model. Sketch the diagram, build the table, and take the empty and doubtful cells to the product owner. Ask the developers which transitions the code actually allows; it often differs from the requirement.

Keep the state table with your test cases as testware, with stable ids for states, events and transitions, and report coverage in those terms: "7 of 7 valid transitions, 9 of 12 invalid transitions attempted". A defect report for a failed transition names the start state, the event, the expected state and the actual state.

Practice exercise

Model an expense claim workflow

Your task

An expense tool has this requirement: "A claim starts as Draft; its owner can delete it while it is Draft or submit it for review. The manager approves a submitted claim or returns it to Draft with comments. A claim above 5,000 SAR also needs approval by Finance after the manager. Finance pays approved claims."

Build the state model, design the fewest test cases that reach 100% valid transitions coverage, and choose the invalid transitions you would attempt first. Then enter your transitions in the State Transition Generator, one per line such as Draft --submit--> Submitted, and compare its state table and invalid-transition tests with yours.

Show the model answer
Model answer

States: S1 Draft (start), S2 Submitted, S3 Awaiting Finance, S4 Approved, S5 Paid (end), S6 Deleted (end). Transitions: T1 S1 → S2 submit; T2 S2 → S1 return; T3 S2 → S4 approve [amount ≤ 5,000]; T4 S2 → S3 approve [amount > 5,000]; T5 S3 → S4 Finance approves; T6 S4 → S5 pay; T7 S1 → S6 delete.

Three test cases cover all seven transitions and all six states: TC-01 (1,200 SAR) submit, return, delete — T1, T2, T7; TC-02 (5,000.00 SAR) submit, approve, pay — T1, T3, T6; TC-03 (5,000.01 SAR) submit, approve, Finance approves, pay — T1, T4, T5, T6. The two amounts test both sides of the guard.

Invalid transitions to attempt first, one per test case: pay a claim in S2 (not approved); pay a claim in S5 again (double payment); Finance approves a claim in S2, skipping the manager; delete a claim in S4. Each must be refused, with the state unchanged.

Questions: can Finance return a claim, and to which state? If a returned claim's amount changes, is the guard checked again?

Frequently asked questions

Is a state diagram the same as a flowchart?

No. A flowchart shows the steps of a process in order. A state diagram shows the conditions an object can be in and the events that move it between them, so the same event can lead to different results in different states. Many workflows need both: a flowchart for the user's path and a state model for the object's status.

What is the difference between 0-switch and 1-switch coverage?

0-switch coverage exercises every single valid transition. 1-switch coverage exercises every pair of consecutive valid transitions, such as T3 followed by T2: a wrong code and then the correct one. The three test cases above never run that pair, so they would miss a defect where one wrong attempt invalidates the code. 1-switch needs more test cases and goes beyond the three criteria of the Foundation syllabus. The State Transition Generator can generate test cases for both.

When should I use state transition testing?

Whenever the response to an event depends on what happened before: anything with a status field (orders, claims, tickets), accounts and sessions, subscriptions, multi-step wizards, devices with modes, and API resources whose status changes. When the result depends only on the current combination of inputs, a decision table fits better.

Do I have to test every invalid transition?

Full all transitions coverage requires attempting every invalid transition that can be triggered. Outside mission- and safety-critical software, teams usually choose by risk: the ones a user or an API client can trigger, and those that would move money, data or access. Record the ones you skip and why.

References

  • ISTQB Certified Tester Foundation Level (CTFL) v4.0ISTQB · 2023The foundation syllabus of software testing: test levels and types, test design techniques, test management and tools.
  • ISTQB GlossaryISTQBThe standard definitions of testing terms — test case, regression testing, severity, priority, boundary value analysis and the rest.

Practise with Mutqan tools

Define states and events, then generate a transition table, valid/invalid transition tests and 0-switch/1-switch coverage.

Test Design

Generate structured test cases (id, title, preconditions, steps, expected result, priority) from a feature description and field list.

Test Design

Generate boundary values (min-1, min, min+1, nominal, max-1, max, max+1) for numeric and length constraints.

Test Design

Go deeper

Your progress on this topic

Part of the QA Roadmap