TDD for state machines
04 Jan 2013, 10:01
Jan Suchotzki (1 post)
Hi, as I searched already quite a bit on the WWW without any major success, hopefully you guys can help me a little.
I’m working on some smaller controllers and currently without any OS. This leaves me with the task that some time consuming activities need to be split into smaller parts. So main is not blocked for a longer time. Usually I try to do this with state machines. Thus my modules (let’ say for reading/writing EEPROM) have some methods for triggering certain tasks (read, write, …), an execute method to process the state machine and an IsCompleted method to determine whether the triggered task is accomplished. Not sure whether this is from a design aspect a good idea, but it works okay. Now the obvious problem is writing some good tests for that. In order to test certain parts of the state machine I need to trigger the task and then need to call execute “several” times. Moreover it is then pretty difficult or event not possible to assert whether I’m in the expected state. This seems to have some obvious disadvantages for creating and especially maintaining the tests.
Any ideas how to better design/implement the modules so that testing gets easier and more maintainable?
Thanks a lot and enjoy embedded development in 2013!
PS: Hope the question isn’t too generic.
04 Feb 2013, 07:18
Arnd R.Strube (53 posts)
I have had good success using QPC / QPN, doing most testing off-target with CppUTest. You may want to have a look at the book “Practical UML Statecharts in C/C++, Second Edition” to get an idea.
Whether or not using the QP framework is an option in your situation obviously I can’t tell, but even if not, the book is the best I’ve seen on state machines, especially hand-coded ones. If you can use QP, you will be thrilled by how simple hierarchichal SMs can be in code.
As for your question, I even run multiple tests on single-instance SMs in C, because the initialization will put it back in the initial state cleanly. In CPP, I tend to use new/delete for tests, even if production code does not.
Also, you can test your state machines in and out of task. Generally, I let the state machine and my tests run in the same task, but it is possible to let the SMs run in a separate task (main task for tests)
Finally, QP uses the idea of a “Board Support Package”. This basically contains calls for all the I/O stuff. It allows you to test off-target whether certain calls have occured, without any need for hardware.
Off-target, I have put in tracing macros that would allow me to tell which event occured in what state, but I’d recommend against using these in tests. You don’t want to re-write your tests every time you redesign the inside of your SMs. Generally, I find it a better approach to test for the outcome of a certain sequence of events. About the only exception is the “initial” pseudo state. Apart from that, I use the trace prints for manual inspection rather than for testing.
I am doing this out of personal interest at the moment. My target is a TI eZ430 Chronos. I have one active SM (own task) and a bunch of “apps” that run inside the main SM (this makes sense because only one “app” can use I/O at any one time).
I am not using SMs at driver level yet. I would like to run unit tests at that level, too, but am not quite sure yet as to which tools to use. Anything like “printf” or “cout” would pretty much have to limit itself to “PaSS”, “FaIL” and the number of errors, if any.
I hope this might give you some new ideas, Arnd
|You must be logged in to comment|