See also: [State Transition Review](/codex/state-transition-review).
State Machine Testing models the system as a state machine with a set of states and transitions between them. State machine testing focuses on testing all possible transitions of a certain fixed length (for example all transition sequences of 1-2 transitions).
### Worked example
Let's look at the OpenZeppelin Counters implementation.
-- CODE language-solidity --
/**
* @title Counters
* @author Matt Condon (@shrugs)
* @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
* of elements in a mapping, issuing ERC721 ids, or counting request ids.
*
* Include with `using Counters for Counters.Counter;`
*/
library Counters {
struct Counter {
// This variable should never be directly accessed by users of the library: interactions must be restricted to
// the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
// this feature: see https://github.com/ethereum/solidity/issues/4637
uint256 _value; // default: 0
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
We can immediately identify each state by the number `_value` and three possible transitions:
- `increment` which moves us from state `n` to `n + 1`
- `decrement` which moves us from state `n` to `n - 1`
- `reset` which moves us from state `n` to `0` .
Let's assume we want to test all 2-sequences of transitions. In that case we still have `MAX_UINT256` possible states to test which is too many. Instead, by using [Equivalence Partitioning](/codex/equivalence-partitioning) and [Boundary Value Analysis](/codex/boundary-value-analysis), we can identify two equivalence classes `{0}` and `1+` with 4 meaningful starting states to test:
- `0` – boundary value
- `1` – boundary value
- `93588` – representative value of equivalence class
- `MAX_UINT256` – boundary value.
For each starting states we could test the 9 possible combinations of transitions.