• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • C++程序的單元測試

    發表于:2007-06-26來源:作者:點擊數: 標簽:
    測試驅動開發 ( TDD )是以測試作為開發過程的中心,它堅持,在編寫實際代碼之前,先寫好基于產品代碼的測試代碼。開發過程的目標就是首先使測試能夠通過,然后再優化設計結構。測試驅動開發式是 極限編程 的重要組成部分。XUnit,一個基于測試驅動開發的 測

    測試驅動開發(TDD)是以測試作為開發過程的中心,它堅持,在編寫實際代碼之前,先寫好基于產品代碼的測試代碼。開發過程的目標就是首先使測試能夠通過,然后再優化設計結構。測試驅動開發式是極限編程的重要組成部分。XUnit,一個基于測試驅動開發的測試框架,它為我們在開發過程中使用測試驅動開發提供了一個方便的工具,使我們得以快速的進行單元測試。XUnit的成員有很多,如JUnit,PythonUnit等。今天給大家介紹的CppUnit即是XUnit家族中的一員,它是一個專門面向C++的測試框架。

     本文不對CppUnit源碼做詳細的介紹,而只是對CppUnit的應用作一些介紹。在本文中,您將看到:

    1、CppUnit源代碼的各個組成部分。
    2、怎樣設置你的開發環境以能夠使用CppUnit。
    3、怎樣為你的產品代碼添加測試代碼(實際上應該反過來,為測試代碼添加產品代碼。在TDD中,先有測試代碼后有產品代碼),并通過CppUnit來進行測試。

    本文敘述背景為:CppUnit1.9.0, Visual C++ 6.0, Windows2000。文中敘述有誤之處,敬請批評指正。

     一、CppUnit源碼組成

     CppUnit測試框架的源代碼可以到 http://sourceforge.net/projects/cppunit/ 上下載。下載解壓后,主要的文件夾有:

    • doc: CppUnit的說明文檔。另外,代碼的根目錄,還有三個說明文檔,分別是INSTALL,INSTALL-unix,INSTALL-WIN32.txt。
    • examples: CpppUnit提供的例子,也是對CppUnit自身的測試,通過它可以學習如何使用CppUnit測試框架進行開發。
    • include: CppUnit頭文件。
    • src: CppUnit源代碼目錄。

    二、初識CppUnit測試環境

     解壓源代碼包后,您一定急著想看看CppUnit到底是個什么樣?Ok,下面我們就來揭開CppUnit的神秘面紗:

     1、進入example文件夾,用VC打開examples.dsw。我們先來看看CppUnit自帶的測試例子。這些例子都是針對CppUnit自身的單元測試集,一方面這是CppUnit作者開發CppUnit框架過程中寫的測試用例,另一方面,我們可以通過這些例子來學習如何在我們自己的工程中添加測試用例。

     2、將CppUnitTestApp工程設為Active Project(Win32 Debug),編譯后運行,則可以看到CppUnit的基于GUI方式進行單元測試TestRunner的界面。點擊“Run”, 這是一個針對CppUnit的單元測試結果,它表明剛才我們做了11個測試,全部通過。 點擊“Browse”,我們還可以選擇想要進行的單元測試。

     CppUnit將所有的單元測試按照樹的結構來表示。在CppUnit中,最小的測試單元,稱為TestMethod測試方法,而多個相關的測試方法又可以組成一個TestCase測試用例。多個測試用例又組成TestSuite測試包。測試包互相嵌套在一起,就形成了上面我們看到的樹結構。我們可以選擇其中任意的樹節點來進行單元測試。

     3、將CppUnitTestMain工程設置為Active Project(Win32 Debug),編譯并運行,我們來看看另一個單元測試的環境這是一個基于文本方式的單元測試環境。CppUnit提供了幾種測試環境,一種基于文本,一種基于GUI。

     4、將HostApp工程設置為Active Project(Win32 Debug),編譯運行。這亦是一個對CppUnit自身進行的測試,只不過它向我們演示的是各種失敗的測試。在基于GUI的測試環境中,若測試不成功,進度條顯示紅色,反之則為綠色。從測試結果我們可以看到失敗的單元測試名稱,引起測試不能通過的原因,以及測試失敗的語句所在的文件及所在行數。

    三、CppUnit開發環境設置

     認識了CppUnit的測試環境,想必你已經是在磨拳擦掌,準備在你的開發過程中感受一下測試驅動開發的感覺了。不過,在使用CppUnit前,還需要設置一下你的開發環境。

     1、CppUnit的lib和dll
     
     CppUnit為我們提供了兩套框架庫,一個為靜態的lib,一個為動態的dll。
     cppunit project:靜態lib
     cppunit_dll project:動態dll和lib
      
     在開發中我們可以根據實際情況作出選擇。進入src文件夾,打開CppUnitLibraries.dsw。分別編譯這兩個project,輸出位置均為lib文件夾。
      
     另外一個需要關注的project是TestRunner,它輸出一個dll,提供了一個基于GUI 方式的測試環境,即前面我們提到的兩種測試環境之一。我們也需要編譯這個project,輸出位置亦為lib文件夾。

     為了方便開發,我們把這些編譯出來的lib和dll(包括Debug版和Release版) copy 到我們自己建立的一個文件夾中(當然你也可以不這么做),例如F:\cppunit1.9.0\lib\,同時我們也把CppUnit源代碼中include文件夾copy到我們自己的include文件夾下。然后在VC的tools/options/directories/include files和library files中設置include路徑和lib路徑。最后別忘了在你的project中link正確的lib。

     2、在你的VC project中打開RTTI開關。
     具體位置Project Settings/C++/C++ Language。

     3、為TestRunner.dll設置環境變量
     TestRunner.dll為我們提供了基于GUI的測試環境。為了讓我們的測試程序能正確的調用它,TestRunner.dll必須位于你的測試程序的路徑下。但最簡單的方法是在操作系統的環境變量Path中添TestRunner.dll的路徑,這樣是最省事的。

     四、你的第一個TDD example

     一切準備就緒,現在我們可以來看看怎樣添加測試代碼了。前面我們提到過,CppUnit最小的測試單位是TestCase,多個相關TestCase組成一個TestSuite。要添加測試代碼最簡單的方法就是利用CppUnit為我們提供的幾個宏來進行(當然還有其他的手工加入方法,但均是殊途同歸,大家可以查閱CppUnit頭文件中的演示代碼)。這幾個宏是:

     CPPUNIT_TEST_SUITE() 開始創建一個TestSuite
     CPPUNIT_TEST() 添加TestCase
     CPPUNIT_TEST_SUITE_END() 結束創建TestSuite
     CPPUNIT_TEST_SUITE_NAMED_REGISTRATION() 添加一個TestSuite到一個指定的TestFactoryRegistry工廠感興趣的朋友可以在HelperMacros.h看看這幾個宏的聲明,本文在此不做詳述。

     1、一個實現兩個整數相加的類
     假定我們要實現一個類,類名暫且取做CPlus,它的功能主要是實現兩個數相加(多簡單的一個類啊,這也要測試嗎?不要緊,我們只是了解怎樣加入測試代碼來測試它就行了,所以越簡單越好)。 假定這個類要實現的相加的方法是:
     int Add(int nNum1, int nNum2);
     Ok,那我們先來寫測試這個方法的代碼吧。TDD 可是先寫測試代碼,后寫產品代碼(CPlus)的哦!先寫的測試代碼往往是不能運行或編譯的,我們的目標是在寫好測試代碼后寫產品代碼,使之編譯通過,然后再進行重構。這就是Kent Beck說的“red/green/refactor”( 還記得基于GUI的測試環境的狀態條嗎?)。所以,上面的類名和方法應該還只是在你的心里,還只是你的idea而已。

     2、在VC中為測試代碼建立一個 Project
     通常,測試代碼和被測試對象是處于不同的Project中的。這樣就不會讓你的產品代碼被測試代碼所“污染 ”。
     在本例中,我們將建立一個基于GUI 方式的測試環境。在VC中,我們建立一個基于對話框的Project。別忘了link正確的lib,本例中我們使用靜態的CppUnit lib。由于我們希望這個Project運行后顯示的是圖2這樣的界面,所以我們需要在App的 Instance()中屏蔽掉原有的對話框,代之以CppUnit的GUI。

    clearcase/" target="_blank" >cccccc>CppUnit::MfcUi::TestRunner runner;
    runner.addTest(PlusTest::suite()); //添加測試
    runner.run(); //show UI
    /*
    CCPlusTestDlg dlg;
    m_pMainWnd = &dlg;
    int nResponse = dlg.DoModal();
    if (nResponse == IDOK)
    {
    // TODO: Place code here to handle when the dialog is
    // dismissed with OK
    }
    else if (nResponse == IDCANCEL)
    {
    // TODO: Place code here to handle when the dialog is
    // dismissed with Cancel
    }
    */

    前面我們提到過,TestRunner輸出圖2這樣的對話框,這也是前面我們為什么要為TestRunner.dll的路徑設置環境變量的原因。

     注意:PlusTest::suite()返回一個指向CppUnit::Test的指針.這個指針就是整個測試的起點。
     CppUnit::TestFactoryRegistry::getRegistry()根據TestSuite的名字返回TestFactoryRegistry工廠,然后調用工廠里的makeTest()對TestSuite進行組裝,這是個遞歸調用,將建立起一個樹狀的測試結構。

    namespace PlusTest
    { CppUnit::Test* suite()
    { CppUnit::TestFactoryRegistry ?istry =
    CppUnit::TestFactoryRegistry::getRegistry(plusSuiteName());
    return registry.makeTest(); }}

    另外別忘加頭文件:

    #include "CPlusTestSuite.h"
    #include
    #include

    3、在Project中加入一個類,取名CPlusTestCase CPlusTestCase從CppUnit::TestCase繼承,代碼如下:

    class CPlusTestCase : public CppUnit::TestCase
    { CPPUNIT_TEST_SUITE(CPlusTestCase);
    CPPUNIT_TEST(testAdd);
    CPPUNIT_TEST_SUITE_END();
    public:
    CPlusTestCase();
    virtual ~CPlusTestCase();
    void testAdd(); //測試方法};
    看到這幾個宏了嗎?它們可是在這大顯身手了一把。
    CPPUNIT_TEST_SUITE(CPlusTestCase);
    CPPUNIT_TEST( testAdd );
    CPPUNIT_TEST_SUITE_END();

    通過這幾個宏,我們就把CPlusTestCase和testAdd注冊到了測試列表當中。另外,我們需要在Cpp文件中加入另外一個宏:
    CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CPlusTestCase,PlusTest::plusSuiteName() );

     它將CPlusTestCase這個TestSuite注冊到一個指定的TestFactory工廠中,這個TestSuite用PlusTest::plusSuiteName()函數返回的名字來標識(前面介紹的suite()函數中就是通過這個名字來獲取這個工廠的)。plusSuiteName()是PlusTest這個namespace下的一個函數,它返回我們為這個TestSuite建立的名字(本例我們取名為“plus”)。其實我們也可以不用這么做,直接在宏里寫入“plus“即可。但是這樣可以防止硬編碼帶來的麻煩。

     在測試類中,我們添加了一個測試方法:
     void testAdd();
     它測試的對象是前面提到的CPlus類的方法:
     int Add(int nNum1, int nNum2);
     我們來看看它的實現:
     void CPlusTestCase::testAdd()
     { CPlus plus;
     int nResult = plus.Add(10, 20); //執行Add操作
     CPPUNIT_ASSERT_EQUAL(30, nResult); //檢查結果是否等于30}
     CPPUNIT_ASSERT_EQUAL是一個判斷結果的宏。CppUnit中類似的其它宏請查閱TestAssert.h,本文在此不做詳述 。
     另外,我們還可以覆寫基類的 setUp()、tearDown()兩個函數。這兩個函數實際上是一個模板方法,在測試運行之前會調用setUp()以進行一些初始化的工作,測試結束之后又會調用tearDown()來做一些“善后工作” ,比如資源的回收等等。當然,你也可以不覆寫這兩個函數,因為它們在基類里定義成了空方法,而不是純虛函數。另外,Cpp中要加入頭文件:
    #include "plusSuite.h"

    4、根據測試代碼編寫產品代碼
     編寫完上面的測試代碼后,進行編譯。編譯肯定通不過,編譯器會告訴我們CPlus類沒有聲明,因為我們還沒有實現CPlus類呢!現在的工作就是馬上實現CPlus類,讓編譯通過?,F在你應該嗅到一點“測試驅動“的味道了吧?

     在VC中建立一個MFC Extension Dll的Project,在這個Project 中加入類CPlus,它的聲明如下:

    class AFX_EXT_CLASS CPlus
    {public:
    CPlus();
    virtual ~CPlus(); public:
    int Add(int nNum1, int nNum2);};

    僅有一個方法,就是我們的測試代碼要測試的那個方法。來看看它的實現:
     int CPlus::Add(int nNum1, int nNum2)
     {return nNum1+nNum2;}

    非常簡單,不是嗎?現在讓前面那個包含測試代碼的Project dependent這個Project,include 相關頭文件 ,Rebuild All,你會發現編譯已通過。你體會到了測試代碼驅動產品代碼了嗎?當然我們的這個例子還很簡單 ,沒有重構這一步驟。
    運行我們的測試程序,你就會看到界面:

     單擊”Browse”,
     這下你應該對前面我們說的TestSuite的名字理解更深了吧。plus是一個測試包TestSuite,它的下面包含一個測試用例,這個測試用例下面又包含一個測試方法。
     至此,我們對CppUnit測試框架的應用作了一個詳細的介紹,希望能對你在進行TDD過程中有所幫助。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>