Test driven development, and class design, from first principles (using C++)
Archive - Originally posted on "The Horse's Mouth" - 2014-12-30 14:50:59 - Graham EllisI'm teaching OO / class design from first principles today ... in stages. The chosen source language is C++, but the principles are well applied across other OO languages too.
Stage 1 - write your test program to make sure it works for your customers want to do. Remember that the "customer is king" and that's why you're doing the job! Try to ensure that you have calls available to do everything your customer will want, and create multiple objects with different values in them to ensure you are really storing object and not class (static) variables correctly. [source]
Stage 2 - define the API (Application Progammer interface) to ensure the test compiles and your interface is clearly defined. [source]
Stage 3 - write the code of the class to implement the public members. This is the stage at which you'll be writing the detailed code that will be used by your customers later on - you'll be encapsulating the algorithms in object methods so the customer won't have to be concerned later with the internal detail. Also at stage 3, you'll probably find yourself adding extra (private and / or protected) members to your API. [source]
Stage 4 - get the code to report on whether the test program worked. The code at stage 1 probably (should have!) output results, but manual checking of those to make sure they're still right at a later date will be tedious, so you'll code tests into your test harness to give a clear "worked / failed" flag. [source]
Stage 5 - use functions to avoid stage 4 being very repetitive indeed! [source] and at this stage I also added a further accessor to demonstrate passing stings in and out - which meant an extra test routine too. [source]
Stage 6 - the test evaluation code will itself become a standard object. Stages 5 and 6 can be combined once you're familiar with OO principles, but an object that checks other objects (and a singleton pattern to boot) may be one step too many all at once if you're moving from a structured programming background. [source]
Stage 7 - separate the various pieces into different files so you can use the class without the tests in a real, live application! If you've done a good job of your test suite object, you'll want to package that up separately too so that you can reuse it for other classes and make steps 4 5 and 6 much easier in the future. In this final example of the series, I have also added command line options to allow the test program to be run to print results, to print test output, or to do both.
Source for the final example
[here] for the test program
[here] for the class being tested
[here] for its header file
[here] for the test pattern class
[here] for its header file
Here are the build instructions I used
g++ -c Hotel007.cpp
g++ -c HotelRoomBooking.cpp
g++ -c TestPattern.cpp
g++ -o Hotel Hotel007.o HotelRoomBooking.o TestPattern.o
And here are some sample outputs:
munchkin:cpp_dec14 grahamellis$ ./Hotel
Hotel Rooms Demo
John Smith 360 60
Tinka Belle 883.5 147.25
------------------------------
Testing ++++++
Tests passed 6; tests failed 0
munchkin:cpp_dec14 grahamellis$ ./Hotel -v
Hotel Rooms Demo
John Smith 360 60
Tinka Belle 883.5 147.25
munchkin:cpp_dec14 grahamellis$ ./Hotel -t
------------------------------
Testing ++++++
Tests passed 6; tests failed 0
The fundamentals shown above will work for just about any language, and be a starting point for just about any classes - indeed you are welcome (with the proviso that it's at your risk) to make use of my test harness and to extend it. In practise, what I'm showing you is all the complex setup stuff and I'm not making particularly full use of it by supporting and testing a lot of methods - but such is a training example that my code has made the points needed already.