Many know Jeff Atwood, some know his rule of three. Yes! Yet another golden rule, you need to memorize in your coding adventure.
Ladies and gentlemen here it is The Rule Of Three
Now, that we have laid the basis let's consider who could be the first audience.
How about being an audience to ourselves by unit testing our API?
I hear you saying that this not by the book unit testing and I agree. According to the definition unit tests should exercise individual units of source code. These are commonly understood as a functions or class methods. However, nothing stands in the way of crafting a larger snippets of code, which would use our API in a real-life flow and integrate it into our build acceptance test suite.
Recently, I have had a chance to write an event manager for the framework I am working on. This task required me to develop multiple interfaces: producer, consumer, event manager, event messages.
I have designed everything "on paper", wrote a code, compiled and was satisfied with the work being partially done.
The project I am working on has a requirement to push code only with unit tests. So I started to write my test suite. That's where I got hit by my "design decisions" or lack of them.
Unit tests I was developing were testing some basic real-life flows: add producers to event manager, add consumers, add messages, raise events etc. Since the design was mainly focused on interfaces and the implementation was done in abstract classes, I needed to implement classes that derive from producer, consumer, and messages class. That is how my dummy classes (DummyProducer, DummyConsumer, etc.) were created.
It turned out that I did not include a object lifetime and ownership into consideration, which is not a trivial issue in the C++. I was using references to pass a producer into event manager, but it turned out to be a complete failure. Some refactoring and I switched to shared pointers - which I consider a good solution (for now) - since it is safer in asynchronous event handling.
Next, the message. Sure, I can pass the message, but what about its payload? Who should control the payload lifetime? It turned out I needed to create a proxy class, that stored the payload (which can differ from event to event) and pass it to the event carrying class.
The above examples were some of the more significant issues I have found in my design, there were even more minor details I needed to polish.
I was working on an embedded system for the framework project and it took a while to setup unit test environment. In addition to that, my test suites seem more like an example application than standard unit test. Was it worth it to over-complicate testing like this? I would said yes! It let me gain the perspective to and put myself in API users shoes. Definitely I would do that again!