2/02/2007

TDD'ing State Machines

I'm an electrical engineer. Everything in programming seems to be very very hard for me. Last week I spent 40 hours in aeroplanes, so I had some quality reading time. I did read Agile Estimating and Planning and Test-Driven Development from cover-to-cover. I had quickly gone through them earlier, but this was enlightening experience.

First of all, I have told that we have been trying to figure out effective TDD for our FW development. To be honest, we've struggled. We wrote tests for a state machine implementation. We expected the tests to be run in certain sequence, and that the state was always left where it should be after the test. We of course ended up in lot of rework on test code when our state machine design emerged. We thought that we need to design the state machine up-front in order to be able effectively write tests for it. This did not sound like test driven development at all. This required some more thorough thinking.

So back to my flight. Kent Beck writes that coupling is bad also between tests. A test should leave the system as it was. So writing unit tests in the same sequence as you expect your state machine to work does not seem like a right thing to do. You should be able to execute individual tests and to change the order of individual tests. So instead we are starting to recognize a single state as something to test.

Ph.D. Miro Samek writes about state machines being a killer app for function pointers. He further defines a design pattern for state chart implementation. Our state chart interface has become to be something like:

construct()
dispatch(event)

construct is self explaining and dispatch dispatches new event. We have specific event tick that gives resource time to state machine every 10ms (based on our 50Hz mains). We could also implement a timeout as OS service, and not to have local counters for timed events. Anyway, if we implement each state as a function as Mr. Samek proposes, and we hold our state as a function pointer we can write

dispatch( me, event )
{
me.myState(event);
}

We get rid of cryptic switch -structures. This solution helps us to unit test each state as a function with natural feel.

I'm going to write some benchmarking code to see the actual overhead, but at the moment I like this idea.

1 comment:

JWalker said...

Hello,

I am just trying to figure how to test our state machines and found your post. The idea to test states instead of the whole state machine is interesting.

Our state machines use linked lists of C structs that describe states and transitions. Each transition has exit_state action, transition action and entry_state action.

This makes me think that object of TDD should be the transitions, not the whole state machine.