The approach to FSM-based code is a bit different from that used traditionally. It is very similar to what's described here for hardware testing (which is typically also an FSM).
In short, you create a test input sequence (or a set of test input sequences) which should not only produce a certain output, but also when producing a particular "bad" output lets identifying the failed component by the nature of failure. The approach is quite scalable, the more time you spend on the test design the better the test will be.
This kind of testing is closer to what is called "functional tests" but it eliminates the need to change tests every time you slightly touch an implementation.