/////////////////////////////////////////////////////////////////// // suite.cpp -implements test harness classes, Suite and // // ver 2.0 TestSuiteError // // // // Language: Visual C++, ver 6.0, SP 4 // // Platform: Dell XPS1000, Windows 2000 Professional, SP 1 // // Author: Jim Fawcett, CST 2-187, Syracuse University // // jfawcett@twcny.rr.com, 315-443-3948 // // Source: // // The origianl design and implementation are by Chuck // // Allison (see ref, below), but I have modified his code // // and so take responsibility for this product. // /////////////////////////////////////////////////////////////////// // Notes: // // - This is a demonstration of a test harness that provides // // semi-automated low-level testing. // // - Goal is to run a suite of tests that return pass/fail // // information. // // - The intent is that you will use the test harness after // // every modification to your code, getting quick evidence // // that the change did or did not break anything. // // // // - To use the harness you have to implement simple test // // classes, derived from class Test, provided by the harness. // // - You then declare an instance of class Suite, provided // // by this module and add an instance of each test class. // // The test harness: // // - sequences through all your tests, // // - keeps records of passes and failures // // - handles display of the results // // // // Reference: // // The Simplest Automated Unit Test Framework That Could // // Possibly Work, Chuck Allison, C/C++ Users Journal, // // September 2000 // /////////////////////////////////////////////////////////////////// // #include "suite.h" #include #include #include using namespace std; //----< construct TestSuiteError instance >---------------------- // // derives from C++ standard exception class // class TestSuiteError : public logic_error { public: TestSuiteError(const string& s = "") : logic_error(s) {} }; //----< add a test to the test suite >--------------------------- void Suite::addTest(Test* t) throw(TestSuiteError) { // Make sure test has a stream: if (t == 0) throw TestSuiteError("Null test in Suite::addTest"); else if (m_osptr != 0 && t->getStream() == 0) t->setStream(m_osptr); m_tests.push_back(t); t->reset(); } //----< add a whole suite of tests to this suite >--------------- void Suite::addSuite(const Suite& s) throw(TestSuiteError) { for (size_t i = 0; i < s.m_tests.size(); ++i) addTest(s.m_tests[i]); } //----< used to delete tests created on heap >------------------- void Suite::free() { // This is not a destructor because tests // don't have to be on the heap. for (size_t i = 0; i < m_tests.size(); ++i) { delete m_tests[i]; m_tests[i] = 0; } } // //----< run all tests in suite >--------------------------------- void Suite::run() { reset(); for (size_t i = 0; i < m_tests.size(); ++i) { assert(m_tests[i]); m_tests[i]->run(); } } //----< report test results >------------------------------------ long Suite::report() const { if (m_osptr) { long totFail = 0; *m_osptr << "\n Suite \"" << m_name << "\"\n ======="; size_t i; for (i = 0; i < m_name.size(); ++i) *m_osptr << '='; *m_osptr << "="; for (i = 0; i < m_tests.size(); ++i) { assert(m_tests[i]); totFail += m_tests[i]->report(); } *m_osptr << "\n ======="; for (i = 0; i < m_name.size(); ++i) *m_osptr << '='; *m_osptr << "="; return totFail; } else return getNumFailed(); } //----< return number of successful tests >---------------------- long Suite::getNumPassed() const { long totPass = 0; for (size_t i = 0; i < m_tests.size(); ++i) { assert(m_tests[i]); totPass += m_tests[i]->getNumPassed(); } return totPass; } // //----< return number of unsuccessful tests >-------------------- long Suite::getNumFailed() const { long totFail = 0; for (size_t i = 0; i < m_tests.size(); ++i) { assert(m_tests[i]); totFail += m_tests[i]->getNumFailed(); } return totFail; } //----< reset all test statistics >------------------------------ void Suite::reset() { for (size_t i = 0; i < m_tests.size(); ++i) { assert(m_tests[i]); m_tests[i]->reset(); } } // //----< test classes >------------------------------------------- #ifdef TEST_SUITE class myTest1 : public Test { public: myTest1(ostream *osptr) : Test(osptr) { } void run() { _test(true); _test(false); } }; class myTest2 : public Test { public: myTest2(ostream *osptr) : Test(osptr) { } void run() { _test(3==3); _test(3==5); } }; //----< test entry point >--------------------------------------- void main() { cout << "\n Testing Suite class " << "\n =====================\n"; Suite s("Test Suite", &cout); myTest1 test1(&cout); s.addTest(&test1); myTest2 test2(&cout); s.addTest(&test2); s.run(); s.report(); cout << "\n\n"; } #endif