On Aug 11, 2008, at 10:11 PM, James G. wrote:
would be possible to test that outer layer, the real work. The
statemachine is just an implementation detail anyway, right? I
mean, maybe it would be hard, but you could probably replace it with
a different strategy. As long as the work still got done, of
course. Can you test that?
This is what I am doing at the moment. I am sending the object events
and testing for the side effects. Nearly all of the work it is
performing is visible as a side effect on a mock. For example, if I
send it a parameter_update_event it moves to the ParameteChange
decision state and then the ModeChange decision state before it lands
in the correct “mode” state. I exposed just enough of the internals
soI can assert that object.fsm.state.should == :correct_state.
Another more complex side effect is when I sent it a
price_update_event. It moves from Standby to PriceCalculation decision
state. If the update presents a good “opportunity,” the machine moves
to a state where it steps through all of the logic for spawning off
other objects to handle the opportunity, otherwise it goes to rest in
the Standby state awaiting a new event.
Last night I broke one of my machines up into smaller bites. It
appears as though each machine gets pretty tough to test beyond 4
states. Here’s an example of what I mean. This before block has to
setup a bunch of mocks so each side effect guides the machine through
the steps that I need it to go.
describe BidQuoter, “superstate :continuous, :standby_continuous
@q = BidQuoter.new
@worker = mock(“quoter worker”, :null_object => true)
@bar = mock(“bar”)
@edge = mock(“edge”)
@order = mock(“order”)
@parameter = mock(“parameter”)
@trade = mock(“trade”)
@q.worker = @worker # a sub fsm
# send these two events to drive the machine to the correct state
2 or 3 “it should” blocks
All that setup is required to get the machine into a state where I can
then send more specific events and verify it is creating the right
side effects and transitioning to the right states. Several of those
mocks are used in the “it should” blocks that come afterwards but I
set them up here because they are used multiple times. This setup
block gets longer the “deeper” I get into the machine and test each
branch with more mocks being created and additional assertions being
assigned to them.
Ugh… state machines make it very simple to layout the logic but
testing it is an absolute mess. All of this “setup” is a classic code
smell but I don’t see any alternative right now. I’m betting that I am
missing a simple technique or heuristic for managing this better.