Comment on page
Debugging your FSM
FSM2 provides a number of tools to help debug your FSM.
Firstly we strongly recommend that you only use the static transitions (i.e. don't use onDynamic). As yet we have found no use cases where onDynamic is needed and it makes debugging your FSM much harder.
The first thing you should ALWAYS check is that your FSM is consistent.
statemachine.analysis();
You should create a unit test that tests your statemachine.
import 'package:fsm2/fsm2.dart';
import 'package:test/test.dart';
void main() {
test('export', () async {
final machine = _createMachine();
expect(await machine.analyse(), equals(true));
});
}
StateMachine _createMachine() {
return StateMachine.create((g) => g
..initialState<Heating>()
..state<DoorOpen>((b) {})
..state<Heating>((b) => b
..on<OpenDoor, DoorOpen>()
..state<Toasting>((b) {})
..state<Baking>((b) {})));
}
class DoorOpen extends State {}
class Toasting extends State {}
class Baking extends State {}
class Heating extends State {}
class LightOn extends State {}
class OpenDoor extends Event {}
class OnTurnOff extends Event {}
If you have followed our recommendation to not use 'onDynamic' then you can create a visualisation of your FSM.
void main() {
final machine = _createMachine();
await machine.export('test/test.gv');
}
We are not big fans of humongous state machines. Rather we recommend that you create a statemachine for each part of your code.
You might have an FSM for each screen or particular db updates but avoid the temptation to model your entire app as a single statemachine. This will never end well.
The statemachine allows you to hook every transition by calling 'onTransition'.
StateMachine.create((g) => g
..initialState<Solid>()
..state<Solid>((b) => b
..on<OnMelted, Liquid>(sideEffect: (e) => watcher.log(onMeltedMessage))
..onEnter((s, e) => watcher?.onEnter(s))
..onExit((s, e) => watcher?.onExit(s)))
..onTransition((fromState, event, toState) => print('${fromState} ${event} ${toState} ')));
The above code prints the eventType, fromState, and toState for every transition.
A single event can result in multiple transitions if your state machine is in a concurrent region.
We provide a number of helper functions that make it easier to unit test your statemachine.
- StateMachine.waitUntilQuiescent
- StateMachine.isInState
- StateMachine.stateOfMind
test('test fsm', () async {
final machine = _createMachine<Solid>(watcher);
machine.applyEvent(OnMelted());
// wait for the event to have been applied
await machine.waitUntilQuiescent;
expect(machine.isInState<Liquid>(), equals(true));
});
Last modified 3mo ago