How to write test cases for spaghetti code, trying not to resort into spaghetti code as well.
Using Boost SML in order to avoid typical massive if else or switch case logic which tends to grow out of any kind of control after several feature additions.
Besides, it's possible to visualize that state machine into automatically generated PlantUML diagrams in order to discuss corner cases or just feedback the usual Doxygen, Markdown, or Wiki pages documentation. In a perfect word, that plantuml diagrams should generate c++ code.
The trickiest point is to process all the typeid info into something more human friendly. Only g++ solution is implemented on this example but it seems to work as well for macos clang++.
Developers try to avoid writting spaghetti code as much as possible in order to make their lives easier when it comes down to debugging in the future but life is a bitch:
Even if you start with a clean design and it got implemented in the cleanest if else logic ever, you're doomed to add new funtionality along the time. 'Doomed' is not the correct word, you're 'lucky' your application is a big success with lots of users asking for new features and you got no time to refactor all your original design just to add an 'extra' branch into your if else logic.
At the same time, taking for granted you keep up your test cases to those changes, they can suffer the very same out-of-control grow with more and more corner cases to cover. Or there aren't any sort of test cases associated to current new features and you must begin from scratch for them, tempted to copy & paste previous old cases and modify them with more if else branches.
In that scenario it's where you might tackle your testing with a different approach: think abstractly about the real business model in your code under test, get the simplest (and easier to maintain) State Machine possible and write test cases testing that state machine. Don't forget to generate all the UML diagrams in order to discuss failing tests or just get ready for future code refactoring.
Boost SML state machine as the following:
*"idle"_s + event<event1> = "state1"_s
, "state1"_s + event<event2> [ guard ] / action = "state2"_s
, "state2"_s + event<event3> [ guard ] = "state1"_s
, "state2"_s + event<event4> / action = X
Can be automatically dumped as a UML diagram:
@startuml logic.png
[*] --> idle
idle --> state1 : event1
state1 --> state2 : event2 [guard] / action
state2 --> state1 : event3 [guard]
state2 --> [*] : event4 / action
@enduml
To be converted into a png:
java -jar /opt/plantuml/plantuml.jar -o images/ README.md
That looks like:
Test cases based on documented UML state machines are easier to maintain and it can make the difference when it comes to refactoring your base code in the future: