Flylib.com

Books Software

 
 
 

11.3 Books

     

11.3 Books

Numerous books have been published about Agile Development, unit testing, and specific unit test frameworks. A few of them are listed here:

  • Test Driven Development: A Practical Guide , by David Astels (Prentice Hall)

  • Test Driven Development: By Example , by Kent Beck (Addison-Wesley)

  • Test-Driven Development in Microsoft .Net , by James A. Newkirk and Alexei Vorontsov (Microsoft Press)

  • Testing Extreme Programming , by Lisa Crispin (Addison-Wesley)

  • Pragmatic Unit Testing in C# with NUnit , by Andy Hunt and Dave Thomas (The Pragmatic Programmers)

  • Pragmatic Unit Testing in Java with JUnit , by Andy Hunt and Dave Thomas (The Pragmatic Programmers)

  • Unit Testing in Java How Tests Drive the Code , by Johannes Link (Morgan Kaufmann)

  • Agile Software Development: Principles, Patterns, and Practices , by Robert Martin (Prentice Hall)

  • JUnit in Action , by Vincent Massol and Ted Husted (Manning Publications)

     

Appendix A. Simple C++ Unit Test Framework

This appendix contains the C++ version of the simple unit test framework example from Chapter 2. The software architecture of the C++ version is identical to that of the Java version. The only variations are those dictated by the differences in language syntax.

The full description of the example is found in Chapter 2. This appendix simply describes how to build and run the C++ version. It assumes that you are using the GNU g++ compiler. Most other C++ compilers should work as well, but the compilation commands may vary from what is shown here.

     

A.1 Example 1: Create a Book

The first example creates the class Book . En route, the unit test framework is built and the first unit test written.

A.1.1 Step 0: Set Up the Unit Test Framework

The framework initially is built on a single class, UnitTest , shown in Figure A-1. The source code for UnitTest includes a header file, UnitTest.h , and an implementation file, UnitTest.cpp , as shown in Example A-1.

Figure A-1. The class UnitTest
figs/utf_aa01.gif

Example A-1. The class UnitTest
UnitTest.h

#define UT_ASSERT( condition ) \

        assertTrue(condition,__FILE__,__LINE_  _,#condition)



class

UnitTest

{



 public:



   virtual ~UnitTest( ) {}

   virtual void

runTest

( ) = 0;



 protected:



   void

assertTrue

(bool condition, const char *file, 

                  int line, const char *msg);

   static int

num_test_success

;



};



UnitTest.cpp

#include <stdio.h>

#include <stdlib.h>

#include "UnitTest.h"



int UnitTest::

num_test_success

= 0;



void UnitTest::

assertTrue

(bool condition, 

                           const char *file, int line, 

                           const char *msg) {

   if (!(condition)) {

      printf("FAILURE!\n");

      printf("%s:%d:%s\n", file, line, msg);

      exit(1);

   }

   ++num_test_success; 



}

UnitTest is an abstract class because it contains the pure virtual function runTest( ) . Actual unit tests will be inherited from UnitTest and must override the runTest( ) method. The function assertTrue( ) should be used to test Boolean conditions in runTest( ) . If the condition is TRUE , the counter num_test_success is incremented. If it is FALSE , the function test_failure() is called. This function reports the file location of the failure and exits. The macro UT_ASSERT() is used in place of direct calls to assertTrue( ) . It uses the preprocessor directives __FILE_ _ and __LINE_ _ to fill in the location of the call at compilation, and the #condition argument allows the conditional expression to be printed in the failure report.

Compile UnitTest with the command g++ -c UnitTest.cpp (or your compiler's equivalent command).

A.1.2 Step 1: Create a Unit Test

Start by creating the unit test class BookTest , as shown in Example A-2.

Example A-2. The definition of the class BookTest
BookTest.h

#include "UnitTest.h"

#include "Book.h"



class

BookTest

: public

UnitTest

{



 public:



   void

runTest

( ) {

      Book book("Cosmos");

      UT_ASSERT(!strcmp(book.title, "Cosmos"));

   }



};

The unit test BookTest constructs an instance of the class Book , passing the title as an argument, and then tests the value of the book's title attribute. Since the entire implementation of BookTest is present in BookTest.h , no .cpp file is necessary.

BookTest is instantiated and run by a class called TestRunner , which also contains the main( ) method for the test framework. Example A-3 shows the implementation of TestRunner .

Example A-3. The class TestRunner
TestRunner.cpp

#include "stdio.h"

#include "BookTest.h"



int

main

( ) {



   BookTest test;

   test.runTest( );

   printf("SUCCESS!\n");

   return 0;



}

Compile TestRunner . The compiler will report that it cannot find the file Book.h , and that the class Book is undeclared. No surprise there! So, the next step is to create the most basic implementation of the class Book that will allow the code to compile, as shown in Example A-4.

Example A-4. Initial version of the class Book
Book.h

#include "string.h"



class

Book

{



 public:



   Book(const char* title) {}



   char title[255];



};

The class TestRunner should compile now. The test framework and the unit test are in place. To run the test, link the objects together into an executable:

g++ -o TestRunner TestRunner.o UnitTest.o

Execute TestRunner . The following result is reported :

FAILURE!

BookTest.h:9:!strcmp(book.title, "Cosmos")

This failure demonstrates that the unit test framework is working. Note how the UT_ASSERT() macro captures the file's name and location, as well as the code contents of the test assertion.

A.1.3 Step 2: Create a Book

BookTest fails because Book does not yet contain the functionality being tested . In this step, the minimum necessary code to achieve unit test success is added.

The constructor for Book is changed to set the title attribute, as shown in Example A-5.

Example A-5. The class Book with title attribute set by the constructor
Book.h

#include "string.h"



class Book {



 public:



   Book(const char* title) {

      strcpy(this->title, title);

   }



   char title[255];



};

A.1.4 Step 3: Test Again

The final step is to rebuild the code, re-run the unit test, and see whether the changes produce the desired results.

Rebuild and execute TestRunner . The results of BookTest are reported:

SUCCESS!

An instance of Book can now be created and given a title.