CppUnit 使用說明

eXtreme Programming (XP)

What is Extreme Programming?

Extreme Programming is a discipline of software development based on values of simplicity, communication, feedback, and courage. It works by bringing the whole team together in the presence of simple practices, with enough feedback to enable the team to see where they are and to tune the practices to their unique situation.
Ron Jeffries 11/08/2001

test

The best XP teams treat their customer tests the same way they do programmer tests: once the test runs, the team keeps it running correctly thereafter. This means that the system only improves, always notching forward, never backsliding.

Note: unit testing, function testing, stress testing

CppUnit - C++ port of JUnit

XUnit is a unit testing framework originally developed by Kent Beck in the paper "Simple Smalltalk Testing:With Patterns" and ported to many platforms with the help of many independent groups.

CppUnit download page: 1.6.2 src doc 2001/10/20

JUnit home page

CppUnit 在 VC++ 6.0 上的安裝與測試

步驟如下:

  1. 解壓縮 cppunit-1_6_2_tar.gz 到自己指定的資料夾內 (例如: vc98\cppunit162, 資料夾 vc98\ 為你的機器上 VC 安裝的資料夾, 解壓縮後包括 bin, include, lib, doc 等資料夾), 解壓縮 cppunit-docs-1_6_2_tar.gz 到 vc98\cppunit162\docs 內 (此為線上參考資料: vc90\cppunit162\docs\index.html)

  2. 編譯 TestRunner 應用程式(具 Win32 GUI) (TestRunner??.dll), 及 CppUnit 與 DSPlugIn 類別函式庫 (CppUnit??.lib 與 TestRunnerDSPlugIn??.dll)

  3. 測試 1:快速應用測試同時安裝 Visual Studio IDE 環境中的 add-ins

  4. 測試 2:完整測試 CppUnit 各個函式功能 CppUnitTestApp 是一個 MFC 程式, 裡面有所有 CppUnit 功能的測試, 也是一個完整的範例程式

  5. 設定 Visual Studio 的 include directory 及 lib directory, 如此以後經由此 IDE 界面編譯的程式都可以順利地找到 CppUnit include 檔及函式庫
    Tools/Options, Directories, Include Files 增加 vc98\cppunit162\include 及 vc98\cppunit162\include\msvc6,
    Tools/Options, Directories, Library Files 增加 vc98\cppunit162\lib
這樣子可以省事一點, 但是也使得 workspace/project 沒有辦法帶到其它機器上去工作。

參考文件:

    vc98\cppunit162\INSTALL-WIN32.txt

使用 CppUnit 及 TestRunner

製作一個新的 Project 時如何使用 CppUnit 及 TestRunner

  1. 修改 Project/Settings

  2. 應用程式可以決定要不要使用 TestRunner GUI 類別來觀看結果
    不使用 TestRunner 類別時主要有三種方法

    1. 需要測試函式的類別先繼承 CppUnit::TestCase 類別, 然後 override runTest() 函式, 在其中加上測試碼, 例如:
        --- ComplexNumberTest.h --- #include <cppunit/TestCase.h> #include "Complex.h" using namespace std; using namespace CppUnit; class CComplexNumberTest : public TestCase { public: CComplexNumberTest(string name) : TestCase (name) {} protected: void setUp() { TRACE("setUp()\n"); } void runTest() { TRACE("runTest()\n"); CPPUNIT_ASSERT (CComplex (10, 1) == CComplex (10, 1)); CPPUNIT_ASSERT (!(CComplex (1, 1) == CComplex (2, 2))); } void tearDown() { TRACE("tearDown()\n"); } }; --- Complex.h --- class CComplex { public: friend bool operator==(const CComplex& a, const CComplex& b); public: CComplex(double r, double i = 0) : m_real(r), m_imaginary(i) {} private: double m_real, m_imaginary; }; --- Complex.cpp --- bool operator==(const CComplex& a, const CComplex& b) { return (a.m_real == b.m_real) && (a.m_imaginary == b.m_imaginary); } --- Method1View.cpp --- void CMethod1View::OnInitialUpdate() { CView::OnInitialUpdate(); CComplexNumberTest *tc = new CComplexNumberTest("test name"); tc->run(); delete tc; }
      測試結果上面這個方法會順序執行 setUp(), runTest(), 及 tearDown(), 但是 runTest() 中所有的 CPPUNIT_ASSERT() 並沒有作用???? 而且執行過後記憶體有 memory leakage???

    2. CComplexNumberTest 類別中的所有資料設定我們稱為一個 fixture, 也就是一種測試資料的組合, 我們在此類別中可以設計一些測試的成員函式 testXXXX(), 它們基本上每一個都是獨立的, 我們可以利用 TestCaller 類別來獨立測試每一個函式, 每一個函式在測試前 TestCaller 都會產生新的 CComplexNumberTest 的物件, 依序執行 ctor(), setUp(), testXXXX(), tearDown(), 及 dtor()
        #include <cppunit/TestCase.h> #include <cppunit/TestCaller.h> ... class ComplexNumberTest : public TestCase { private: Complex *m_10_1, *m_1_1, *m_11_2; public: void setUp() { m_10_1 = new Complex(10, 1); m_1_1 = new Complex(1, 1); m_11_2 = new Complex(11, 2); } void tearDown() { delete m_10_1, delete m_1_1, delete m_11_2; } void testEquality() { CPPUNIT_ASSERT(*m_10_1 == *m_10_1); CPPUNIT_ASSERT(!(*m_10_1 == *m_11_2)); } void testAddition() { CPPUNIT_ASSERT(*m_10_1 + *m_1_1 == *m_11_2); } }; ... TestCaller<ComplexNumberTest> test1("testEquality", &ComplexNumberTest::testEquality); test1.run (); TestCaller<ComplexNumberTest> test2("testAddition", &ComplexNumberTest::testAddition); test2.run ();

    3. 上面 TestCaller 物件可以藉由 TestSuite 物件來集合在一起測試
        #include <cppunit/TestSuite.h> #include <cppunit/TestCaller.h> #include <cppunit/TestResult.h> ... TestSuite suite; TestResult result; suite.addTest(new TestCaller<ComplexNumberTest> ("testEquality", &ComplexNumberTest::testEquality)); suite.addTest(new TestCaller<ComplexNumberTest> ("testAddition", &ComplexNumberTest::testAddition)); suite.run (&result);

      TestSuite 物件也可以再透過其它的 TestSuite 物件來集合起來一起測試, 例如:

        TestSuite suite; TestResult result; suite.addTest (ComplexNumberTest::suite ()); suite.addTest (SurrealNumberTest::suite ()); suite.run (&result); ... suite() 函式範例如下: public: static Test *suite () // Note: TestSuite is derived from Test { TestSuite *suiteOfTests = new TestSuite; suiteOfTests->addTest( new TestCaller<ComplexNumberTest> ("testEquality", testEquality)); suiteOfTests->addTest( new TestCaller<ComplexNumberTest> ("testAddition", testAddition)); return suiteOfTests; }

    4. 或是藉由另外一個 TextTestRunner 類別的物件來完成測試:
        #include <cppunit/TextTestRunner.h> #include <cppunit/extensions/TestFactoryRegistry.h> ... int main( int argc, char* argv[] ) { CppUnit::TextTestRunner runner; runner.addTest(CppUnit::TestFactoryRegistry:: getRegistry().makeTest()); runner.run(); return 0; }
    以上測試都會開啟一文字視窗來顯示結果。

    如果要使用 Win32 GUI TestRunner 類別時主要有兩種方法:

    1. 各個 TestCase 及 TestSuite 定義同前所述:
        #include <msvc6/testrunner/TestRunner.h> ... TestRunner runner; runner.addTest (ExampleTestCase::suite ()); runner.addTest (ComplexNumberTest::suite ()); runner.run ();

    2. 利用 include/cppunit/extensions/HelperMacros.h 中定義的 CPPUNIT_TEST_SUITE() CPPUNIT_TEST() CPPUNIT_TEST_SUITE_END() 等巨集來加入一個一個測試,例如:
        #include <cppunit/extensions/HelperMacros.h> ... CPPUNIT_TEST_SUITE( XXXXTest ); CPPUNIT_TEST( testRoutine1 ); CPPUNIT_TEST( testRoutine2 ); CPPUNIT_TEST_SUITE_END();
      並用
        CPPUNIT_TEST_SUITE_REGISTRATION( XXXXTest );
      來登錄,然後使用 cppunit/extensions/TestFactoryRegistry.h 中的 TestFactoryRegistry 來產生 TestSuit, 範例如下:
        #include <msvc6/testrunner/TestRunner.h> #include <cppunit/extensions/TestFactoryRegistry.h> ... TestRunner runner; runner.addTest(CppUnit::TestFactoryRegistry:: getRegistry().makeTest()); runner.run();

參考文件:

  1. vc98\cppunit162\INSTALL-WIN32.txt

  2. vc98\cppunit162\examples\msvc6\HostApp\*.*
    especially,

  3. vc98\cppunit162\examples\msvc6\CppUnitTestApp\*.*

  4. vc98\cppunit162\examples\cppunittest\*.*

  5. vc98\cppunit162\docs\cookbook.html

  6. vc98\cppunit162\docs\index.html

  7. Martin Fowler's Refactoring Chapter 4

C++ 程式設計課程 首頁
視窗系統程式設計課程 首頁

製作日期: 11/13/2001 by 丁培毅 (Pei-yih Ting)
E-mail: pyting@cs.ntou.edu.tw TEL: 02 24622192x6615
海洋大學 理工學院 資訊科學系