# Statemachine gem and unit testing

**URL:** <https://www.ruby-forum.com/t/statemachine-gem-and-unit-testing/145614>\
**Category:** Ruby\
**Created:** [August 12, 2008, 4:40am UTC](https://www.ruby-forum.com/t/statemachine-gem-and-unit-testing/145614 "2008-08-12T04:40:08Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![cremes](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19b73/32.png) [@cremes](https://www.ruby-forum.com/u/cremes)\
**Post date:** [August 12, 2008, 4:40am UTC](https://www.ruby-forum.com/t/statemachine-gem-and-unit-testing/145614/1 "2008-08-12T04:40:08Z")

</div>

I’ve been using the statemachine gem [1] to build out some finite  
state machines for some work I am doing. I generally use rspec for  
most of my spec driven development, but I confess to having a bit of  
trouble wrapping my head around how to write specs for these  
statemachines.

For very simple 1 to 3 state machines, spec’ing the behavior is  
relatively simple. However, when the machines start getting more  
complex with nested superstates and more than a few transitions,  
spec’ing the behavior quickly gets out of control. Throw in a few  
decision states that can branch 2+ ways and my head is fit to explode.

I’ve been writing the specs iteratively. Each time I add a state, the  
#before block gains a few more lines to “drive” the machine to that  
specific state so I can test its behavior. Obviously this block gets  
pretty unwieldy after just a few semi-complex states. The specs that  
ship with the gem are not much help in this regard; they are very  
simple.

The obvious answer is to decompose every machine so none are larger  
than 3 states (or so), but then it pushes the complexity out to  
handling the interaction between those machines. Another approach  
would be to break encapsulation and allow the specs to setup the state  
directly without “driving” the machine to populate the values, but  
that just feels _wrong_.

Any ideas? Example code would be appreciated! 🙂

cr

---

<div class="post-metadata">

**Author:** ![cremes](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19b73/32.png) [@cremes](https://www.ruby-forum.com/u/cremes)\
**Post date:** [August 12, 2008, 5:14am UTC](https://www.ruby-forum.com/t/statemachine-gem-and-unit-testing/145614/2 "2008-08-12T05:14:36Z")

</div>

On Aug 11, 2008, at 9:37 PM, Chuck R. wrote:

> I’ve been using the statemachine gem [1] to build out some finite  
> state machines for some work I am doing.

This is an absolutely excellent point you have raised about a very  
real problem. I totally confess that I’m just throwing out an idea  
here, so feel free to ignore this if it’s unhelpful.

You did say the statemachine is for some work. I’m wondering if it  
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?

Good luck with your problem?

James Edward G. II

---

<div class="post-metadata">

**Author:** ![cremes](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19b73/32.png) [@cremes](https://www.ruby-forum.com/u/cremes)\
**Post date:** [August 12, 2008, 1:02pm UTC](https://www.ruby-forum.com/t/statemachine-gem-and-unit-testing/145614/3 "2008-08-12T13:02:40Z")

</div>

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  
substate” do  
before(:each) do  
@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”)

@bar  
.should\_receive(:event\_type).any\_number\_of\_times.and\_return(:bar\_update)

@edge  
.should\_receive  
(:event\_type).any\_number\_of\_times.and\_return(:parameter\_update)

@order  
.should\_receive  
(:event\_type).any\_number\_of\_times.and\_return(:order\_update)

@parameter  
.should\_receive  
(:event\_type).any\_number\_of\_times.and\_return(:parameter\_update)

@trade  
.should\_receive  
(:event\_type).any\_number\_of\_times.and\_return(:trade\_update)

```
 @q.worker = @worker # a sub fsm

```

@parameter  
.should\_receive(:key).any\_number\_of\_times.and\_return(:quote\_mode)

@parameter  
.should\_receive(:quote\_mode).any\_number\_of\_times.and\_return(‘c’)  
@edge.should\_receive(:key).any\_number\_of\_times.and\_return(:edge)  
@edge.should\_receive(:edge).any\_number\_of\_times.and\_return(-0.02)  
@q.run(1)

```
 # send these two events to drive the machine to the correct state
 @q.update(@parameter)
 @q.update(@edge)

```

end

# 2 or 3 “it should” blocks

end

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.

cr

---

<div class="post-metadata">

**Author:** ![cremes](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19b73/32.png) [@cremes](https://www.ruby-forum.com/u/cremes)\
**Post date:** [August 13, 2008, 9:23pm UTC](https://www.ruby-forum.com/t/statemachine-gem-and-unit-testing/145614/4 "2008-08-13T21:23:11Z")

</div>

2008/8/12 Chuck R. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> 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.

Chuck, there’s a Google or Yahoo group for test-driven development.  
Maybe you can ask there, too. I’m also interested in this topic, so  
I’d be glad if you could post some results here.

Regards,  
Pit
