Modulo [B]asico para prueba [unit]aria de programas:
|
00001 // test_BUnit.cpp (C) 2006 adolfo@di-mare.com 00002 00003 /** \file test_BUnit.cpp 00004 \brief Test program form class \c BUnit.h 00005 00006 \author Adolfo Di Mare <adolfo@di-mare.com> 00007 \date 2008 00008 */ 00009 00010 #include "BUnit.h" 00011 #include <iostream> 00012 using namespace std; 00013 00014 /// Testing \c BUnit.h 00015 class test_BUnit : public TestCase { 00016 public: 00017 bool run(); 00018 void test_constructor(); 00019 void test_reset(); 00020 void test_addTest(); 00021 void test_run(); 00022 void test_setName(); 00023 void test_testThis(); 00024 void test_BUnit_macro(); 00025 void test_assertTrue_Msg(); 00026 void test_Allison(); 00027 }; 00028 00029 /// Main testing method. 00030 bool test_BUnit::run() { 00031 test_constructor(); 00032 test_reset(); 00033 test_addTest(); 00034 test_run(); 00035 test_setName(); 00036 test_testThis(); 00037 test_BUnit_macro(); 00038 test_assertTrue_Msg(); 00039 test_Allison(); 00040 00041 return wasSuccessful(); 00042 } 00043 00044 /// test_BUnit ==> \c TestCase::TestCase(...). 00045 void test_BUnit::test_constructor() { 00046 {{ // test::constructor() 00047 test_BUnit thisTest; 00048 assertTrue( string::npos != thisTest.getName().find( "test_BUnit" ) ); 00049 assertTrue( thisTest.failureCount() == 0 ); 00050 assertTrue( thisTest.countTestCases() == 1 ); 00051 assertTrue( thisTest.successCount() == 0 ); 00052 assertTrue( thisTest.runCount() == 0 ); 00053 assertTrue( thisTest.failureString() == "" ); 00054 }} 00055 { // Remaining tests 00056 test_BUnit thisTest; 00057 assertTrue( thisTest.m_pass == 0 ); 00058 assertTrue( thisTest.m_failure == 0 ); 00059 assertTrue( thisTest.m_name == 0 ); 00060 assertTrue( thisTest.m_failureList.empty() ); 00061 } 00062 } 00063 00064 /// test_BUnit ==> \c TestCase::reset() + \c TestCase::resetTests(). 00065 void test_BUnit::test_reset() { 00066 {{ // test::reset() 00067 class MyTest : public TestCase { 00068 public: 00069 bool run() { 00070 assertTrue( 1 == 2 ); // Failure !!! 00071 assertTrue( 1 == 1 ); // Ok 00072 assertTrue( 2 == 2 ); // Ok 00073 return wasSuccessful(); 00074 } 00075 }; // MyTest 00076 MyTest thisTest; 00077 for ( int i=0; i<11; ++i ) { 00078 thisTest.run(); // runs the same test 11 times 00079 } 00080 assertTrue( 11 == thisTest.failureCount() ); // ( 1 == 2 ) x 11 00081 assertTrue( 22 == thisTest.successCount() ); // ( 1 == 1 ) && ( 2 == 2 ) 00082 assertTrue( 33 == thisTest.runCount() ); // 33 == 11+22 00083 assertTrue( "" != thisTest.failureString() ); // 11 recorded failures 00084 std::string remember = thisTest.getName(); 00085 00086 thisTest.reset(); // Anula los contadores 00087 00088 assertTrue( 0 == thisTest.failureCount() ); 00089 assertTrue( 0 == thisTest.successCount() ); 00090 assertTrue( 0 == thisTest.runCount() ); 00091 assertTrue( "" == thisTest.failureString() ); 00092 assertTrue( remember == thisTest.getName() ); // reset() won´t change the name 00093 }} 00094 } 00095 00096 /// test_BUnit ==> \c TestSuite<TestCase>::addTest(). 00097 void test_BUnit::test_addTest() { 00098 {{ // test::addTest() 00099 class MyTest : public TestCase { 00100 public: 00101 bool run() { 00102 assertTrue( 1 == 1 ); // Ok 00103 assertTrue( 1 == 2 ); // Failure !!! 00104 return wasSuccessful(); 00105 } 00106 }; // MyTest 00107 TestSuite<TestCase> SSS; 00108 MyTest thisTest, *ptr_test = new MyTest; 00109 SSS.addTest( thisTest ); // addTest(&)==> SSS.~TestSuite<>() will NOT destroy "thisTest" 00110 SSS.addTest( ptr_test ); // addTest(*)==> SSS.~TestSuite<>() WILL destroy "ptr_test" 00111 assertTrue( 0 == SSS.failureCount() ); 00112 SSS.run(); 00113 assertTrue( 1+1 == SSS.failureCount() ); 00114 assertTrue( "" != SSS.toXML() ); 00115 00116 TestSuite<TestCase> TTT, RRR; 00117 TTT.addTest( & SSS ); // similar to TTT.addSuite( SSS ) 00118 assertTrue( "" == SSS.toXML() ); 00119 assertTrue( "" != TTT.toXML() ); 00120 RRR.addTest( TTT ); // similar to RRR.addSuite( TTT ) 00121 assertTrue( 0 == SSS.countTestCases() ); 00122 assertTrue( 0 == TTT.countTestCases() ); // SSS y TTT become "empty" 00123 assertTrue( 2 == RRR.countTestCases() ); 00124 assertTrue( 2 == RRR.failureCount() ); // RRR has it all 00125 assertTrue( "" != RRR.toXML() ); 00126 }} 00127 { // Remaining tests 00128 class MyTest : public TestCase { 00129 public: 00130 bool run() { 00131 assertTrue( 1 == 1 ); // Ok 00132 assertTrue( 1 == 2 ); // Failure !!! 00133 return wasSuccessful(); 00134 } 00135 }; // MyTest 00136 TestSuite<TestCase> SSS, TTT; 00137 MyTest thisTest, *ptr_test = new MyTest; 00138 SSS.addTest( thisTest ); // addTest(&)==> SSS.~TestSuite<>() won´t destroy "thisTest" 00139 SSS.addTest( ptr_test ); // addTest(*)==> SSS.~TestSuite<>() will detroy "ptr_test" 00140 SSS.addTest( ptr_test ); // no duplicates get added 00141 SSS.addTest( ptr_test ); // no duplicates get added 00142 SSS.addTest( (MyTest*)(0) ); // null never get added 00143 SSS.run(); 00144 assertTrue( 2 == SSS.countTestCases() ); 00145 assertTrue( 1+1 == SSS.failureCount() ); // 1 failure for each "TestCase" 00146 00147 TTT.addSuite( *( (TestSuite<TestCase>*)(0) ) ); 00148 TTT.addSuite( TTT ); // no se auto-aniquila 00149 assertTrue( 0 == TTT.countTestCases() ); 00150 00151 TTT.addTest( thisTest ); // addTest(&)==> SSS.~TestSuite<>() won´t destroy "thisTest" 00152 TTT.addTest( ptr_test ); // addTest(*)==> SSS.~TestSuite<>() will detroy "ptr_test" 00153 assertTrue( 2 == TTT.countTestCases() ); 00154 00155 SSS.addTest( new MyTest ); 00156 TTT.addSuite( SSS ); /// SSS se queda vacío 00157 TTT.addSuite( TTT ); TTT.addTest( TTT ); TTT.addTest( & TTT ); 00158 assertTrue( 0 == SSS.countTestCases() ); // original empty 00159 assertTrue( 3 == TTT.countTestCases() ); // no duplicates 00160 00161 TTT.run( ); // ads 3 failures to the previous 2 00162 assertTrue( 000 == SSS.failureCount() ); 00163 assertTrue( 2+3 == TTT.failureCount() ); 00164 thisTest.run(); 00165 assertTrue( 1+2+3 == TTT.failureCount() ); 00166 } 00167 } 00168 00169 /// test_BUnit ==> \c run() + \c runBare(). 00170 void test_BUnit::test_run() { 00171 {{ // test::run() 00172 class MyTest : public TestCase { 00173 int m_val; 00174 public: 00175 MyTest() : m_val(0) {} // init: m_val == 0; 00176 void setUp() { m_val = 1; } 00177 void tearDown() { m_val = 2; } 00178 bool run() { 00179 assertTrue( m_val == 1 ); 00180 return wasSuccessful(); 00181 } 00182 }; // MyTest 00183 TestSuite<TestCase> SSS; 00184 SSS.addTest( new MyTest ); SSS.addTest( new MyTest ); 00185 assertTrue( 2 == SSS.countTestCases() ); 00186 assertTrue( "" == SSS.failureString() ); 00187 00188 SSS.runBare(); // Ok ==> setUp() sets [m_val == 1] 00189 assertTrue( "" == SSS.toXML() ); 00190 00191 SSS.run(); // Failure: [m_val == 2] ==> value set by tearDown() 00192 std::string sssXML = SSS.toXML(); 00193 assertTrue( "" != sssXML ); // SSS contains failures. 00194 assertTrue( sssXML.find("m_val") != string::npos ); 00195 assertTrue( SSS.runCount() == 2+2 ); 00196 }} 00197 } 00198 00199 /// test_BUnit ==> \c getName() + \c setName(). 00200 void test_BUnit::test_setName() { 00201 {{ // test::setName() 00202 class MyTest : public TestCase { 00203 public: 00204 bool run() { 00205 assertTrue( 2 == 2 ); 00206 return wasSuccessful(); 00207 } 00208 }; // MyTest 00209 MyTest thisTest; 00210 assertTrue( "chorlito" != thisTest.getName() ); 00211 thisTest.setName( "chorlito" ); 00212 assertTrue( "chorlito" == thisTest.getName() ); 00213 { 00214 // thisTest.setName( std::string("chorlito") ); // won´t compile 00215 thisTest.setName( std::string("chorlito").c_str() ); // bad practice 00216 std::string V("boom!"); 00217 assertTrue( 0==strcmp( V.c_str() , "boom!") ); 00218 assertTrue( "chorlito" != thisTest.getName() ); // c_str() uses 00219 assertTrue( "boom!" == thisTest.getName() ); // static data 00220 } 00221 }} 00222 } 00223 00224 /// test_BUnit ==> \c testThis(). 00225 void test_BUnit::test_testThis() { 00226 {{ // test::testThis() 00227 class MyTest : public TestCase { 00228 public: 00229 bool run() { 00230 bool dont_copy = false; 00231 testThis( 2 == 2, "2 is 2", __FILE__, __LINE__, dont_copy ); // Ok 00232 testThis( 1 == 2, "1 is 2", __FILE__, __LINE__, dont_copy ); // failure #1 00233 testThis( 2 == 1, "2 is 1", __FILE__, __LINE__, dont_copy ); // failure #2 00234 return wasSuccessful(); 00235 } 00236 }; // MyTest 00237 MyTest thisTest; 00238 assertTrue( thisTest.wasSuccessful() ); // run() has not been executed 00239 thisTest.run(); // 2 failures 00240 assertTrue( thisTest.failureCount() == 2 ); 00241 assertTrue( ! thisTest.wasSuccessful() ); 00242 }} 00243 } 00244 00245 #include <vector> // std::vector 00246 #include <stdexcept> // std::logic_error 00247 00248 /// test_BUnit ==> Macros. 00249 void test_BUnit::test_BUnit_macro() { 00250 {{ // test::BUnit_macro() 00251 class MyTest : public TestCase { 00252 public: 00253 bool run() { 00254 testThis( 2 == 2, "2 == 2", __FILE__, __LINE__ ); // sucess 00255 BUnit_TEST( 2 == 2 ); // same thing using macro BUnit_TEST() 00256 testThis( 1 == 2, "1 == 2", __FILE__, __LINE__ ); // failure #1 00257 assertTrue( 1 == 2 ); // same thing using BUnit_TEST() // failure #2 00258 { // con macros 00259 std::vector<int> V; // "V[]" is empty ==> there is no "V[2]" 00260 try { 00261 int i = V.at(2); // "V[2]" does not exits 00262 BUnit_FAILURE("V.at(2)"); // failure: "at()" didn´t rise the exception 00263 } 00264 catch (std::logic_error&) { 00265 BUnit_SUCCESS(); // correct: "V.at(2)" throws "logic_error" 00266 } // because "V[]" is empty 00267 } 00268 { // no macros 00269 std::vector<int> V; 00270 try { 00271 int i = V.at(2); 00272 recordFailure("V.at(2)" , __FILE__ , __LINE__ ); 00273 } 00274 catch (std::logic_error&) { 00275 recordSuccess(); 00276 } 00277 } 00278 return wasSuccessful(); // Returns "false" 00279 } 00280 }; // MyTest 00281 MyTest thisTest; 00282 assertTrue( thisTest.wasSuccessful() ); // run() has not been executed 00283 thisTest.run(); // 2 failures 00284 assertTrue( thisTest.failureCount() == 2 ); 00285 assertTrue( thisTest.toXML() != "" ); 00286 assertTrue( ! thisTest.wasSuccessful() ); 00287 }} 00288 } 00289 00290 /// test_BUnit ==> \c assertTrue_Msg(). 00291 void test_BUnit::test_assertTrue_Msg() { 00292 {{ // test::assertTrue_Msg() 00293 class MyTest : public TestCase { 00294 enum { N = 6 }; 00295 int m_Matrix[N][N]; 00296 public: 00297 void setUp() { 00298 for ( int i=0; i<N; ++i ) { 00299 for ( int j=0; j<N; ++j ) { 00300 m_Matrix[i][j] = 666; 00301 } 00302 } 00303 } 00304 bool run() { 00305 for ( int i=0; i<N; ++i ) { 00306 for ( int j=0; j<N; ++j ) { 00307 std::string err = "m_Matrix"; 00308 err += '[' + TestCase::toString(i) + ']'; 00309 err += '[' + TestCase::toString(j) + ']'; 00310 err += " == 0"; 00311 assertTrue_Msg( err , m_Matrix[i][j] == 0 ); 00312 } 00313 } 00314 return wasSuccessful(); 00315 } 00316 }; // MyTest 00317 MyTest tester; 00318 tester.runBare(); 00319 assertTrue( ! tester.wasSuccessful() ); 00320 // nunca agrega el mensaje genérico "m_Matrix[i][j] == 0" 00321 assertTrue( string::npos == tester.toString().find( "m_Matrix[i][j] == 0" ) ); 00322 // siempre usa el mensaje específico en el valor de "i-j" 00323 assertTrue( string::npos != tester.toString().find( "m_Matrix[3][5] == 0" ) ); 00324 }} 00325 } 00326 00327 #include <exception> // std::out_of_range 00328 00329 // La especificiacién está más adelantes. 00330 void test_BUnit::test_Allison() { 00331 {{ // test::Allison() 00332 // Stack class for letter -- very simple (<em>Last In First Out</em>). 00333 // - Throws \c std::logic_error on invalid operations. 00334 // - Example inspired in Chuck Allison' work. 00335 // - http://search.yahoo.com/search?n=100&p=Simplest+Unit+Test+Allison 00336 class Stack { 00337 public: 00338 enum { N = 5 /* Max Capacity for the stack */ }; 00339 // Constructor for a stack that can hold up to \c "Stack::N" values. 00340 Stack() : m_top(0) { m_vec[m_top] = 0; } 00341 // Stoes a copy of "v" at the top of the stack. 00342 void push(const char& v) { 00343 if ( m_top != N ) { m_vec[m_top] = v; m_top++; } 00344 else { throw std::out_of_range("Stack::push()"); } 00345 } 00346 // Removes the topmost value from the stack. 00347 void pop() { 00348 if ( m_top>0 ) { m_top--; } 00349 else { throw std::out_of_range("Stack::pop()"); } 00350 } 00351 // Reference to topmost value in the stack. 00352 char& top() { 00353 if ( m_top>0 ) { return m_vec[m_top-1]; } 00354 else { throw std::out_of_range("Stack::top()"); } 00355 } 00356 // Number of values stored in the stack. 00357 unsigned size() const { return m_top; } 00358 private: 00359 char m_vec[N+1] ; // Vector to hold stored values. 00360 int m_top; // Next available vector entry. 00361 }; // Stack 00362 00363 class MyTest : public TestCase { 00364 public: 00365 bool run() { 00366 Stack S; // the stack 00367 00368 try { // empty stack 00369 S.pop(); 00370 fail_Msg("! S.pop()"); 00371 } 00372 catch ( std::out_of_range & ex ) { 00373 assertTrue( 0 == strcmp( ex.what() , "Stack::pop()" ) ); // Ok: empty stack 00374 } 00375 catch (...) { 00376 fail_Msg("! ( std::out_of_range & )"); 00377 } 00378 00379 try { // Pila llena 00380 for (int i=0; true; ++i) { 00381 S.push('0'+i); 00382 assertTrue( S.top() == '0'+i ); 00383 } 00384 fail_Msg("! S.push()"); 00385 } 00386 catch ( std::out_of_range & ex ) { 00387 assertTrue( 0 == strcmp( ex.what() , "Stack::push()" ) ); // Ok: full stack 00388 } 00389 catch (...) { 00390 fail_Msg("! ( std::out_of_range & )"); 00391 } 00392 00393 try { // Vacea la pila 00394 for (int i=Stack::N-1; true; --i) { 00395 assertTrue( S.top() == '0'+i ); 00396 S.pop(); 00397 } 00398 fail_Msg("! S.pop()"); 00399 } 00400 catch ( std::out_of_range & ex ) { 00401 assertTrue( 0 == strcmp( ex.what() , "Stack::top()" ) ); // Ok: empty stack 00402 } 00403 catch (...) { 00404 fail_Msg("! ( std::out_of_range & )"); 00405 } 00406 return wasSuccessful(); 00407 } 00408 }; // MyTest 00409 MyTest thisTest; 00410 thisTest.run(); // 0 failures 00411 assertTrue( thisTest.wasSuccessful() ); 00412 }} 00413 } 00414 00415 // could not put this specification before because \skipline would find it first 00416 /** \fn void test_BUnit::test_Allison(); 00417 \brief test_BUnit ==> \c test_Allison(). 00418 00419 \dontinclude test_BUnit.cpp 00420 \skipline test::Allison() 00421 \until }} 00422 \see test_BUnit::test_Allison() 00423 */ 00424 00425 /// Main program ==> excecutes all tests. 00426 int main() { 00427 if (1) { 00428 test_BUnit test_BUnit_Instance; 00429 test_BUnit_Instance.setUp(); 00430 test_BUnit_Instance.run(); 00431 cout << test_BUnit_Instance.summary() << endl; 00432 cout << test_BUnit_Instance.toString() << endl; 00433 cout << test_BUnit_Instance.toXML() << endl; 00434 00435 TestSuite<TestCase> SSS; 00436 SSS.addTest( test_BUnit_Instance ); 00437 SSS.addTest( new test_BUnit ); 00438 SSS.run(); 00439 cout << SSS.report() << endl; 00440 cout << SSS.toXML() << endl; 00441 00442 TestSuite<TestCase> TTT; 00443 TTT.addTest( SSS ); 00444 TTT.run(); 00445 cout << TTT.summary() << endl; 00446 cout << TTT.toString() << endl; 00447 } 00448 return 0; 00449 } 00450 00451 // EOF: test_BUnit.cpp