unit_test.hpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2004 by Patrick Audley                                  *
00003  *   paudley@blackcat.ca                                                   *
00004  *   modified by Georg Martius (georg.martius@web.de)                      *
00005  ***************************************************************************
00006 # _______________
00007 # VERSION HISTORY
00008 #
00009 # v1.0 (2004/12/28)
00010 #  - prelimary version
00011 # v1.1 (2005/05/30) (By Georg Martius
00012 #  - improved output
00013 #  - improved speed measurement
00014 ##
00015 */
00016 
00017 /** @section C++ Unit Testing Framework
00018  * See implementation in
00019  * @ref unit_test.h
00020  *
00021  * @par
00022  * @section writing Writing Unit Tests
00023  * @par
00024  * Ideally, unit tests are written with the code they test.  The easiest way
00025  * to do this is to include all the unit tests at the bottom of each source
00026  * that they relate too.  It's also possible to create source files of nothing
00027  * but tests to expand coverage across multiple translation modules.
00028  * @par
00029  * Let's take a simple example:  we have a new function that adds two numbers.
00030  * @code
00031  * int addTwoNumbers( int a, int b ) {
00032  *   return a + b;
00033  * }
00034  * @endcode
00035  * To write a unit test that checks that @f$addTwoNumbers(x_1,x_2)=x_1+x_2@f$ we
00036  * would write the unit test like so:
00037  * @code
00038  * #ifdef UNITTEST
00039  * #include "unit_test.h"
00040  *
00041  * UNIT_TEST_DEFINES
00042  *
00043  * DEFINE_TEST( check_two_plus_two ) {
00044  *   unit_assert( "2+2=4", addTwoNumbers(2,2)==4 );
00045  * }
00046  *
00047  * UNIT_TEST_RUN( "addTwoNumbers Tests" )
00048  *   ADD_TEST( check_two_plus_two )
00049  * UNIT_TEST_END
00050  *
00051  * #endif // UNITTEST
00052  * @endcode
00053  * @par
00054  * Now we have a test suite defined that will only be compiled when we define UNITTEST.
00055  * UNIT_TEST_RUN actually creates a main() function that runs the tests so if we put
00056  * this code into a file (say add.cpp) then we can compile and run it like so:
00057 @verbatim
00058 # gcc -DUNITTEST -o unit_test_add add.cpp
00059 # ./unit_test_add
00060 ---[ addTwoNumbers Tests ]---
00061   2+2=4: PASSED
00062 @endverbatim
00063  * @par
00064  * So far so good, let's add a new test that we think will fail.
00065  * @code
00066  * #ifdef UNITTEST
00067  * #include "unit_test.h"
00068  *
00069  * UNIT_TEST_DEFINES
00070  *
00071  * DEFINE_TEST( check_two_plus_two ) {
00072  *   unit_assert( "2+2=4", addTwoNumbers(2,2)==4 );
00073  *   unit_pass();
00074  * }
00075  *
00076  * DEFINE_TEST( check_bogus ) {
00077  *   unit_assert( "1+5=9", addTwoNumbers(1,5)==9 );
00078  *   unit_pass();
00079  * }
00080  *
00081  * UNIT_TEST_RUN( "addTwoNumbers Tests" )
00082  *   ADD_TEST( check_negatives )
00083  * UNIT_TEST_END
00084  *
00085  * #endif // UNITTEST
00086  * @endcode
00087  * Running the unit_test now we get:
00088 @verbatim
00089 # gcc -DUNITTEST -o unit_test_add add.cpp
00090 # ./unit_test_add
00091 ---[ addTwoNumbers Tests ]---
00092   2+2=4: PASSED
00093   1+5=9: FAILED
00094 @endverbatim
00095  * @par
00096  * @section adding Integrating with Automake
00097  * @par
00098  * Automake has the ability to define testing targets that get run when
00099  * issue "make check" command.  Adding these tests are pretty straight
00100  * forward.  For the above we would add this to our Makefile.am:
00101 @verbatim
00102 TESTS = unit_test_add
00103 noinst_PROGRAMS = unit_test_add
00104 CLEANFILES = add_unit.cpp
00105 unit_test_add_SOURCES = add_unit.cpp
00106 
00107 %_unit.cpp: %.cpp
00108         $(CXX) -E -o $*_unit.cpp $*.C @CFLAGS@ -DUNITTEST=1
00109 @endverbatim
00110  * To add addtional unit tests you just modify the first four lines.  For
00111  * example: to add a new unit test suite in the file sub.C we might do this.
00112 @verbatim
00113 TESTS = unit_test_add unit_test_sub
00114 noinst_PROGRAMS = unit_test_add unit_test_sub
00115 CLEANFILES = add_unit.cpp sub_unit.cpp
00116 unit_test_add_SOURCES = add_unit.cpp
00117 unit_test_sub_SOURCES = sub_unit.cpp
00118 @endverbatim
00119  * @section Notes Implementation Notes
00120  * @par
00121  */
00122 
00123 /**
00124  * @file unit_test.h Unit Testing framework for C++
00125  * @author Patrick Audley
00126  * @date December 2004
00127  */
00128 
00129 #ifndef _UNIT_TEST_H
00130 #define _UNIT_TEST_H
00131 
00132 #ifdef UNITTEST
00133 #include <iostream>
00134 #include <vector>
00135 #include <sys/time.h>
00136 #include <sys/resource.h>
00137 #include <sys/types.h>
00138 #include <time.h>
00139 #include <stdio.h>
00140 
00141 
00142 struct rusage ruse;
00143 extern int getrusage();
00144 /** @brief Gets the current CPU time with microsecond accuracy.
00145  *  @returns microseconds since UNIX epoch
00146  */
00147 inline double cputime( void ) {
00148   getrusage( RUSAGE_SELF, &ruse );
00149         return ( ruse.ru_utime.tv_sec + ruse.ru_stime.tv_sec + 1e-6 * (ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec ) );
00150 }
00151 /** @brief Calculates the transactions rate.
00152  *  @param run_time microsecond resolution run time
00153  *  @param transactions number of transactions handled in run_time seconds
00154  *  This is useful if you want to guarantee minimun transactional throughputs in unit tests.
00155  *  @warning This code is obviously very test platform dependent.
00156  */
00157 inline double transactions_per_second( double run_time, unsigned long transactions ) {
00158         return (double)transactions / run_time;
00159 }
00160 /** @brief Prints to stdout the results of timing an event.
00161  *  @param msg to print with the numbers
00162  *  @param run_time microsecond resolution run time
00163  *  @param transactions number of transactions handled in run_time seconds, if 0 then transactional output is suppressed
00164  *  @warning This code is obviously very test platform dependent.
00165  */
00166 inline void print_cputime( double run_time, unsigned long transactions = 0 ) {
00167   
00168   if( transactions == 0 ){
00169         printf("%7.3f seconds CPU time\n", run_time );
00170   }else{
00171     printf("(%li x):  %7.3f seconds CPU time\n", transactions, run_time );
00172     printf("      (%7.3f transactions/second)\n", 
00173            transactions_per_second( run_time, transactions ) );
00174   }
00175 }
00176 
00177 /// typedef for unittest functions
00178 typedef bool(*test_func)(void);
00179 /// typedef for vectors of unittest functions
00180 typedef std::vector< test_func > test_vector;
00181 
00182 /** @brief Start of inline Unit Test definitions
00183  *  Use this to start the list of unit tests.  This should be followed
00184  *  by one or more DEFINE_TEST entries.
00185  */
00186 #define UNIT_TEST_DEFINES \
00187   test_vector * add_test( test_func x ) { \
00188     static test_vector unit_tests; \
00189     if( x != NULL ) unit_tests.push_back( x ); \
00190     return &unit_tests; \
00191   }
00192 
00193 /** @brief Start a new test definition
00194  *  @param test_name Name of the test - must be unique in this unit test suite.
00195  */
00196 #define DEFINE_TEST(test_name) bool unit_test_##test_name (void)
00197 
00198 /** @brief Adds a defined test to test run.
00199  *  @param test_name Test name of a previously defined test to add the the current suite.
00200  *  @sa DEFINE_TEST UNIT_TEST_RUN
00201  *  This should be called after UNIT_TEST_RUN for each defined test.
00202  */
00203 #define ADD_TEST(test_name) add_test( &unit_test_##test_name );
00204 
00205 
00206 /** @brief Starts the timer for CPU time measurement.   
00207  *  @param msg Message that should be printed
00208  *  @param times Number of times the Block should be executed
00209  *  @note Must be terminated with an UNIT_MEASURESTOP statement.
00210  */
00211 #define UNIT_MEASURE_START(msg,times) \
00212   { std::cout << "  -> " <<  msg << std::flush; \
00213     double measure_t1 = cputime(); \
00214     int measure_times = times; \
00215     for(int measure_i=0; measure_i < times; measure_i++){
00216 
00217 /** @brief Stops the timer for CPU time measurement and prints out result 
00218  *  @note Must be terminated with an UNIT_MEASURESTOP statement.
00219  */
00220 #define UNIT_MEASURE_STOP(msg) \
00221     } /* end for */ \
00222     print_cputime(cputime()-measure_t1,measure_times); \
00223   }
00224 
00225 
00226 
00227 /** @brief Start a Unit test run section.
00228  *  @param suite Name for this test suite.
00229  *  @note Must be terminated with an UNIT_TEST_END statement.
00230  */
00231 #define UNIT_TEST_RUN( suite ) \
00232 int main(void) { \
00233   bool result = true; \
00234   std::cout << "---[ " << suite << " ]--- " << std::endl;
00235 
00236 /** @brief Use within a Unit Test to verify a condition.
00237  *  @warning Terminates test on failure.
00238  */
00239 #define unit_assert( msg, cond ) \
00240   { \
00241   char buffer[40]; memset(buffer,32,40); \
00242   int pos = strlen(msg); \
00243   buffer[40- (pos>40 ? 40 : pos)]=0; \
00244   std::cout << "    " << msg << ": " << buffer << std::flush; \
00245   if( !(cond) ) { std::cout << "FAILED!" << std::endl; return false; } \
00246   std::cout << "PASSED" << std::endl; \
00247   }
00248 
00249 /** @brief Use to end a unit test in success.
00250  *  @note Either unit_pass or unit_fail should end every test.
00251  */
00252 #define unit_pass() return true;
00253 
00254 /** @brief Use to end a unit test in failure.
00255  *  @note Either unit_pass or unit_fail should end every test.
00256  */
00257 #define unit_fail() return false;
00258 
00259 /** @brief Finish a Unit Test run section.
00260  */
00261 #define UNIT_TEST_END \
00262   test_vector *_vector = add_test( NULL ); \
00263   for( unsigned short i = 0; i < _vector->size(); i++ ) { \
00264      bool testresult = (*(*_vector)[i])(); \
00265      if( result == true && testresult == false ) { result = false; } \
00266   } \
00267   return !result; \
00268 }
00269 
00270 #endif // UNITTEST
00271 
00272 #endif // _UNIT_TEST_H
Generated on Thu Jun 28 14:45:37 2012 for Robot Simulator of the Robotics Group for Self-Organization of Control by  doxygen 1.6.3