Dear all,
Herewith I’d like to shortly present some of my recent work in the field of unit testing and TDD. The attached patch and latest revision of my BitTorrent patch contain a number of interesting points.
In the spirit of TDD I tried to first identify some tests that describe the behavior of the classes I’m implementing. I was actually working on PacketSession when I figured out I need ConnectionStub and needed to create one. The new Connection would be slightly different than the one we currently have, so I proceeded the TDD style with Protocols::Generics::Connection defined in Protocols/Generics/Connection2.h. The prefix 2 is because of a limitation in qmake, which deserves a post of its own. I wrote just a few of tests for the write function first and then did the implementation to make these tests pass. Then I added tests for the connection establishment and name resolution and made them pass. The new tests I wrote gave me ideas how to improve the tests I have already written. As I was modifying the tests I knew right away what needs to be changed in the implementation. Most of the time I didn’t have any serious difficulties and I only had to go into the debugger twice to figure out what actually goes wrong. In the other cases the cause was obvious.
Writing the tests for connectToNode() was a bit tricky because if a hostname needs to be resolved a Qt service is used and the resolved addresses come asynchronously in a registered slot. This meant that if I wanted to be able to test the name resolution I had to make signals and slots work in the tester. That wasn’t too difficult. All that was required was to create an object of QCoreApplication in main(). The next tricky part was that I had to wait for the name resolution to complete. Furthermore Qt signals and slots must be processed in the meanwhile. Take a look at any of the waitFor* functions in ConnectionStub. I was very concerned before how signal and slots interactions could be tested but now I see that is perfectly doable (and controllable).
Once I got my testWrite* and testConnect* tests to run I wanted to make use of the data test, support for which I recently added to CppUnit. I’ve kept both variant so that you can easily compare. I find that data tests are much more flexible and less writing, especially if you want to test more data sets. The generic test function is maybe more difficult to write but I think it’s worth it. I’d be really happy to get some feedback on how you guys like these data test!
I found out that it is not a good idea to write asserts in dtors. I had an assertion that a connection is disconnected when the object is being deleted. What happened was that when a CPPUNIT_ASSERT fails an exception is thrown and the dtor of my ConnectionStub object is called while the connection was still connected. Maybe we should prefer some kind of logging mechanism instead. Any ideas for a good logging framework?
Regards,
Peter
