For the second example, functionality will be added to add a book to a library and retrieve it. These features will be provided by a Library class. To test Library , the unit test should add a Book to a Library and then get that Book from the Library , thus verifying that the Library contains the Book . The unit test framework also will be modified to report the number of tests run. A.2.1 Step 1: Test Adding a Book to a Library The initial version of LibraryTest is shown in Example A-6. Example A-6. Initial version of LibraryTest LibraryTest.h #include "UnitTest.h" #include "Library.h" class LibraryTest : public UnitTest { public: void runTest ( ) { // Create library Library library; // Add book to library Book *book = new Book( "Cosmos" ); library.addBook( book ); // Lookup book in library Book *book2; book2 = library.getBook( "Cosmos" ); UT_ASSERT( !strcmp(book2->title, "Cosmos") ); } }; LibraryTest is added to TestRunner , as shown in Example A-7. Example A-7. TestRunner modified to run LibraryTest TestRunner.cpp #include "stdio.h" #include "BookTest.h" #include "LibraryTest.h" int main( ) { BookTest test; test.runTest( ); LibraryTest test2; test2.runTest( ); printf("SUCCESS!\n"); printf("%d tests completed successfully\n", UnitTest::getNumSuccess( )); return 0; } Now that more than one unit test is being run, it's useful to report the value of the test success counter. To obtain this value, the accessor function getNumSuccess() is added to UnitTest . Also, a #define block is added so that the compiler doesn't complain about multiple definitions of UnitTest . Example A-8 shows the changes to UnitTest . Example A-8. UnitTest with accessor function getNumSuccess UnitTest.h #ifndef _UNIT_TEST_H_ #define _UNIT_TEST_H_ #define UT_ASSERT( condition ) \ assertTrue(condition,__FILE__,__LINE_ _,#condition) class UnitTest { public: virtual ~UnitTest( ) {} virtual void runTest( ) = 0; static int getNumSuccess( ) { return num_test_success; } protected: void assertTrue(bool condition, const char *file, int line, const char *msg); static int num_test_success; }; #endif A minimal "stub" version of the Library class is created so that LibraryTest can be compiled, as shown in Example A-9. Example A-9. Initial version of Library Library.h #include "Book.h" class Library { public: Library( ); ~Library( ); void addBook( Book *book ); Book* getBook( const char *title ); }; Library.cpp #include "Library.h" Library::Library( ) {} Library::~Library( ) {} void Library::addBook( Book* book ) {} Book* Library::getBook( const char *title ) { return new Book(""); } Compiling and running this code produces the expected LibraryTest failure, as well as the BookTest success: FAILURE! LibraryTest.h:17:!strcmp(book2->title, "Cosmos") 1 tests completed successfully A.2.2 Step 2: Add a Book to a Library The final step is to add the new functionality to Library and verify that the unit test succeeds. Example A-10 shows the Library class with the minimum necessary code to pass LibraryTest . Example A-10. Library with changes to pass LibraryTest Library.h #include "Book.h" class Library { public: Library( ); ~Library( ); void addBook( Book *book ); Book* getBook( const char *title ); private: Book* books; }; Library.cpp #include "Library.h" Library::Library( ) { } Library::~Library( ) {} void Library::addBook( Book* book ) { books = book; } Book* Library::getBook( const char *title ) { return books; } A.2.3 Step 3: Check Unit Test Results Compiling and running this code should demonstrate success for both of the unit tests: SUCCESS! 2 tests completed successfully Note that this example code allocates a new Book but never deletes it, causing a memory leak. The software architecture of the code in this example is shown in Figure A-2. It is identical to the architecture of the Java version. Figure A-2. Object architecture of code in this example |