See also: 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).
Let's look at the OpenZeppelin Counters implementation.
/**
* @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:
incrementwhich moves us from statenton + 1decrementwhich moves us from statenton - 1resetwhich moves us from statento0.
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 and Boundary Value Analysis, we can identify two equivalence classes {0} and 1+ with 4 meaningful starting states to test:
0– boundary value1– boundary value93588– representative value of equivalence classMAX_UINT256– boundary value.
For each starting states we could test the 9 possible combinations of transitions.