青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Just enjoy programming

CppUnit快速入門(轉載)

簡介

測試是軟件開發過程中極其重要的一環,詳盡周密的測試能夠減少軟件BUG,提高軟件品質。測試包括單元測試、系統測試等。其中單元測試是指針對軟件功能單元所作的測試,這里的功能單元可以是一個類的屬性或者方法,測試的目的是看這些基本單元是否工作正常。由于單元測試的內容很基礎,因此可以看作是測試工作的第一環,該項工作一般由開發人員自行完成。如果條件允許,單元測試代碼的開發應與程序代碼的開發同步進行。

雖然不同程序的單元測試代碼不盡相同,但測試代碼的框架卻非常相似,于是便出現了一些單元測試類庫,CppUnit便是其中之一。

CppUnit是XUnit中的一員,XUnit是一個大家族,還包括JUnit和PythonUnit等。CppUnit簡單實用,學習和使用起來都很方便,網上已有一些文章對其作介紹,但本文更著重于講解其中的基本概念和使用方法,以幫助初次接觸CppUnit的人員快速入門。

安裝

目前,CppUnit的最新版本是1.10.2,你可以從下面地址獲?。?/p>http://sourceforge.net/projects/cppunit

解壓后,你可以看到CppUnit包含如下目錄:

config: 配置文件 contrib: contribution,其他人貢獻的外圍代碼 doc: 文檔,需要通過doxygen工具生成,也可以直接從sourceforge站點上下載打包好的文檔 examples:示例代碼 include: 頭文件 lib: 存放編譯好的庫 src: 源文件,以及編譯庫的工程等

然后打開src目錄下的CppUnitLibraries工程,執行build/batch build,編譯成功的話,生成的庫文件將被拷貝到lib目錄下。

你也可以根據需要選擇所需的項目進行編譯,其中項目cppunit為靜態庫,cppunit_dll為動態庫,生成的庫文件為:

cppunit.lib: 靜態庫release版 cppunitd.lib: 靜態庫debug版 cppunit_dll.lib: 動態庫release版 cppunitd_dll.lib:動態庫debug版

要使用CppUnit,還得設置好頭文件和庫文件路徑,以VC6為例,選擇Tools/Options/Directories,在Include files和Library files中分別添加%CppUnitPath%/include和%CppUnitPath%/lib,其中%CppUnitPath%表示CppUnit所在路徑。

做好準備工作后,我們就可以編寫自己的單元測試代碼了。需說明的是,CppUnit所用的動態運行期庫均為多線程動態庫,因此你的單元測試程序也得使用相應設置,否則會發生沖突。

概念

在使用之前,我們有必要認識一下CppUnit中的主要類,當然你也可以先看后面的例子,遇到問題再回過頭來看這一節。

CppUnit核心內容主要包括六個方面,

1. 測試對象(Test,TestFixture,...):用于開發測試用例,以及對測試用例進行組織管理。

2. 測試結果(TestResult):處理測試用例執行結果。TestResult與下面的TestListener采用的是觀察者模式(Observer Pattern)。

3. 測試結果監聽者(TestListener):TestListener作為TestResult的觀察者,擔任實際的結果處理角色。

4. 結果輸出(Outputter):將結果進行輸出,可以制定不同的輸出格式。

5. 對象工廠(TestFactory):用于創建測試對象,對測試用例進行自動化管理。

6. 測試執行體(TestRunner):用于運行一個測試。

以上各模塊的主要類繼承結構如下:

Test TestFixture TestResult TestListener _______|_________ | | | | | TestSuccessListener TestComposite TestLeaf | | | |____________| TestResultCollector TestSuit | TestCase | TestCaller<Fixture> Outputter TestFactory TestRunner ____________________|_________________ | | | | TestFactoryRegistry CompilerOutputter TextOutputter XmlOutputter | TestSuiteFactory<TestCaseType>

接下來再對其中一些關鍵類作以介紹。

Test:所有測試對象的基類。

CppUnit采用樹形結構來組織管理測試對象(類似于目錄樹),因此這里采用了組合設計模式(Composite Pattern),Test的兩個直接子類TestLeaf和TestComposite分別表示“測試樹”中的葉節點和非葉節點,其中TestComposite主要起組織管理的作用,就像目錄樹中的文件夾,而TestLeaf才是最終具有執行能力的測試對象,就像目錄樹中的文件。

Test最重要的一個公共接口為:

virtual void run(TestResult *result) = 0;

其作用為執行測試對象,將結果提交給result。

在實際應用中,我們一般不會直接使用Test、TestComposite以及TestLeaf,除非我們要重新定制某些機制。

TestFixture:用于維護一組測試用例的上下文環境。

在實際應用中,我們經常會開發一組測試用例來對某個類的接口加以測試,而這些測試用例很可能具有相同的初始化和清理代碼。為此,CppUnit引入TestFixture來實現這一機制。

TestFixture具有以下兩個接口,分別用于處理測試環境的初始化與清理工作:

virtual void setUp(); 
virtual void tearDown(); 

TestCase:測試用例,從名字上就可以看出來,它便是單元測試的執行對象。

TestCase從Test和TestFixture多繼承而來,通過把Test::run制定成模板函數(Template Method)而將兩個父類的操作融合在一起,run函數的偽定義如下:

// 偽代碼 
void TestCase::run(TestResult* result)
{
    result->startTest(this); // 通知result測試開始
    if( result->protect(this, &TestCase::setUp) ) // 調用setUp,初始化環境
        result->protect(this, &TestCase::runTest); // 執行runTest,即真正的測試代碼
    result->protect(this, &TestCase::tearDown); // 調用tearDown,清理環境
    result->endTest(this); // 通知result測試結束
}

這里要提到的是函數runTest,它是TestCase定義的一個接口,原型如下:

virtual void runTest();

用戶需從TestCase派生出子類并實現runTest以開發自己所需的測試用例。

另外還要提到的就是TestResult的protect方法,其作用是對執行函數(實際上是函數對象)的錯誤信息(包括斷言和異常等)進行捕獲,從而實現對測試結果的統計。

TestSuit:測試包,按照樹形結構管理測試用例

TestSuit是TestComposite的一個實現,它采用vector來管理子測試對象(Test),從而形成遞歸的樹形結構。

TestCaller:TestCase適配器(Adapter),它將成員函數轉換成測試用例

雖然我們可以從TestCase派生自己的測試類,但從TestCase類的定義可以看出,它只能支持一個測試用例,這對于測試代碼的組織和維護很不方便,尤其是那些有共同上下文環境的一組測試。為此,CppUnit提供了TestCaller以解決這個問題。

TestCaller是一個模板類,它以實現了TestFixture接口的類為模板參數,將目標類中某個符合runTest原型的測試方法適配成TestCase的子類。

在實際應用中,我們大多采用TestFixture和TestCaller相組合的方式,具體例子參見后文。

TestResult和TestListener:處理測試信息和結果

前面已經提到,TestResult和TestListener采用了觀察者模式,TestResult維護一個注冊表,用于管理向其登記過的TestListener,當TestResult收到測試對象(Test)的測試信息時,再一一分發給它所管轄的TestListener。這一設計有助于實現對同一測試的多種處理方式。

TestFactory:測試工廠

這是一個輔助類,通過借助一系列宏定義讓測試用例的組織管理變得自動化。參見后面的例子。

TestRunner:用于執行測試用例

TestRunner將待執行的測試對象管理起來,然后供用戶調用。其接口為:

virtual void addTest( Test *test ); virtual void run( TestResult &controller, const std::string &testPath = "" );

這也是一個輔助類,需注意的是,通過addTest添加到TestRunner中的測試對象必須是通過new動態創建的,用戶不能刪除這個對象,因為TestRunner將自行管理測試對象的生命期。

使用

先讓我們看看一個簡單的例子:

#include <cppunit/TestCase.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>

// 定義測試用例
class SimpleTest : public CppUnit::TestCase
{
public:
    void runTest() // 重載測試方法
    {
        int i = 1;
        CPPUNIT_ASSERT_EQUAL(0, i);
    }
};

int main(int argc, char* argv[])
{
    CppUnit::TestResult r; 
    CppUnit::TestResultCollector rc;
    r.addListener(&rc); // 準備好結果收集器 

    SimpleTest t;
    t.run(&r); // 運行測試用例

    CppUnit::TextOutputter o(&rc, std::cout);
    o.write(); // 將結果輸出

    return 0;
}
編譯后運行,輸出結果為:
!!!FAILURES!!!
Test Results:
Run: 1 Failures: 1 Errors: 0

1) test: (F) line: 18 E:/CppUnitExamples/SimpleTest.cpp
equality assertion failed
- Expected: 1
- Actual : 0

上面的例子很簡單,需說明的是CPPUNIT_ASSERT_EQUAL宏。CppUnit定義了一組宏用于檢測錯誤,CPPUNIT_ASSERT_EQUAL是其中之一,當斷言失敗時,CppUnit便會將錯誤信息報告給TestResult。這些宏定義的說明如下:

CPPUNIT_ASSERT(condition):判斷condition的值是否為真,如果為假則生成錯誤信息。

CPPUNIT_ASSERT_MESSAGE(message, condition):與CPPUNIT_ASSERT類似,但結果為假時報告messsage信息。

CPPUNIT_FAIL(message):直接報告messsage錯誤信息。

CPPUNIT_ASSERT_EQUAL(expected, actual):判斷expected和actual的值是否相等,如果不等輸出錯誤信息。

CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual):與CPPUNIT_ASSERT_EQUAL類似,但斷言失敗時輸出message信息。

CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta):判斷expected與actual的偏差是否小于delta,用于浮點數比較。

CPPUNIT_ASSERT_THROW(expression, ExceptionType):判斷執行表達式expression后是否拋出ExceptionType異常。

CPPUNIT_ASSERT_NO_THROW(expression):斷言執行表達式expression后無異常拋出。

接下來再看看TestFixture和TestCaller的組合使用:

#include <cppunit/TestCase.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestRunner.h>

// 定義測試類
class StringTest : public CppUnit::TestFixture
{
public:
    void setUp() // 初始化
    {
        m_str1 = "Hello, world";
        m_str2 = "Hi, cppunit";
    }

    void tearDown() // 清理
    {
    }

    void testSwap() // 測試方法1
    {
        std::string str1 = m_str1;
        std::string str2 = m_str2;
        m_str1.swap(m_str2);
        
        CPPUNIT_ASSERT(m_str1 == str2);
        CPPUNIT_ASSERT(m_str2 == str1);
    }

    void testFind() // 測試方法2
    {
        int pos1 = m_str1.find(',');
        int pos2 = m_str2.rfind(',');

        CPPUNIT_ASSERT_EQUAL(5, pos1);
        CPPUNIT_ASSERT_EQUAL(2, pos2);
    }

protected:
    std::string     m_str1;
    std::string     m_str2;
};

int main(int argc, char* argv[])
{
    CppUnit::TestResult r; 
    CppUnit::TestResultCollector rc;
    r.addListener(&rc); // 準備好結果收集器 

    CppUnit::TestRunner runner; // 定義執行實體
    runner.addTest(new CppUnit::TestCaller<StringTest>("testSwap", &StringTest::testSwap)); // 構建測試用例1
    runner.addTest(new CppUnit::TestCaller<StringTest>("testFind", &StringTest::testFind)); // 構建測試用例2
    runner.run(r); // 運行測試

    CppUnit::TextOutputter o(&rc, std::cout);
    o.write(); // 將結果輸出

    return rc.wasSuccessful() ? 0 : -1;
}
編譯后運行結果為:
OK (2 tests)

上面的代碼從功能上講沒有什么問題,但編寫起來太繁瑣了,為此,我們可以借助CppUnit定義的一套輔助宏,將測試用例的定義和注冊變得自動化。上面的代碼改造后如下:

#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>


// 定義測試類
class StringTest : public CppUnit::TestFixture
{
    CPPUNIT_TEST_SUITE(StringTest);  // 定義測試包
    CPPUNIT_TEST(testSwap);  // 添加測試用例1
    CPPUNIT_TEST(testFind);  // 添加測試用例2
    CPPUNIT_TEST_SUITE_END();  // 結束測試包定義
    
public:
    void setUp() // 初始化
    {
        m_str1 = "Hello, world";
        m_str2 = "Hi, cppunit";
    }

    void tearDown() // 清理
    {
    }

    void testSwap() // 測試方法1
    {
        std::string str1 = m_str1;
        std::string str2 = m_str2;
        m_str1.swap(m_str2);
        
        CPPUNIT_ASSERT(m_str1 == str2);
        CPPUNIT_ASSERT(m_str2 == str1);
    }

    void testFind() // 測試方法2
    {
        int pos1 = m_str1.find(',');
        int pos2 = m_str2.rfind(',');

        CPPUNIT_ASSERT_EQUAL(5, pos1);
        CPPUNIT_ASSERT_EQUAL(2, pos2);
    }

protected:
    std::string     m_str1;
    std::string     m_str2;
};

CPPUNIT_TEST_SUITE_REGISTRATION(StringTest); // 自動注冊測試包

int main(int argc, char* argv[])
{
    CppUnit::TestResult r; 
    CppUnit::TestResultCollector rc;
    r.addListener(&rc); // 準備好結果收集器 

    CppUnit::TestRunner runner; // 定義執行實體
    runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
    runner.run(r); // 運行測試

    CppUnit::TextOutputter o(&rc, std::cout);
    o.write(); // 將結果輸出

    return rc.wasSuccessful() ? 0 : -1;
}

CppUnit的簡單介紹就到此,相信你已經了解了其中的基本概念,也能夠開發單元測試代碼了。

轉自:http://blog.csdn.net/freefalcon/article/details/753819

posted on 2012-03-01 20:25 周強 閱讀(264) 評論(0)  編輯 收藏 引用 所屬分類: 軟件工程

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产三级| 亚洲经典自拍| 欧美一区三区二区在线观看| 99国内精品久久| 99精品欧美一区| 一区二区日韩精品| 亚洲一区二区三区四区在线观看| 亚洲一区尤物| 久久久五月天| 欧美交受高潮1| 国产精品久久久久高潮| 国产精品人成在线观看免费| 韩日精品视频| 亚洲美女区一区| 欧美在线视频网站| 男女av一区三区二区色多| 亚洲缚视频在线观看| 一本色道久久88亚洲综合88| 午夜精品福利在线| 欧美激情一区二区三区高清视频 | 欧美精品18videos性欧美| 欧美日韩精品伦理作品在线免费观看 | 一本色道久久综合亚洲精品高清| 一区二区三区视频在线| 欧美色网在线| 国产日韩在线不卡| 亚洲美女中文字幕| 久久国产日韩| 99热这里只有成人精品国产| 久久精品亚洲一区二区| 欧美三级电影网| 在线看一区二区| 午夜精品视频在线观看一区二区 | 欧美国产一区二区在线观看| 亚洲午夜一级| 欧美久久久久| 亚洲国产精品ⅴa在线观看| 亚洲小少妇裸体bbw| 欧美va天堂va视频va在线| 亚洲在线观看| 欧美午夜在线视频| 一区二区电影免费在线观看| 欧美14一18处毛片| 欧美一区二区三区电影在线观看| 欧美日韩国产一级| 99视频超级精品| 亚洲国产成人一区| 麻豆av一区二区三区| 国产一区二区三区免费观看 | 亚洲欧洲日本专区| 开心色5月久久精品| 国内精品国语自产拍在线观看| 亚洲摸下面视频| 国产精品99久久久久久久vr | 国产精品日韩专区| 亚洲一区bb| 中日韩美女免费视频网站在线观看| 欧美aⅴ99久久黑人专区| 在线电影国产精品| 米奇777超碰欧美日韩亚洲| 久久精品中文字幕免费mv| 狠狠色综合播放一区二区 | 日韩午夜激情| 欧美激情一区二区三区在线视频 | 午夜在线a亚洲v天堂网2018| 国产精品―色哟哟| 欧美专区亚洲专区| 久久国内精品视频| 在线观看视频日韩| 欧美国产日韩xxxxx| 欧美大片在线影院| 99国产成+人+综合+亚洲欧美| 亚洲电影欧美电影有声小说| 欧美成人一区二区| 亚洲视频在线看| 亚洲欧美国产毛片在线| 久久一区中文字幕| 亚洲精品男同| 一本久道久久综合婷婷鲸鱼 | 亚洲精品乱码久久久久| 亚洲精品一区二| 欧美性天天影院| 久久gogo国模啪啪人体图| 久久亚洲欧美国产精品乐播| 亚洲精品视频啊美女在线直播| 亚洲伦伦在线| 国产日产精品一区二区三区四区的观看方式 | 狠狠色丁香婷婷综合影院| 欧美高清在线视频| 国产精品国产福利国产秒拍| 久久精品成人一区二区三区| 蜜臀a∨国产成人精品| 亚洲欧美另类中文字幕| 久久久久国产精品一区二区| 日韩一级在线| 欧美一区中文字幕| 日韩视频在线永久播放| 亚洲小说欧美另类社区| 在线观看一区视频| 在线一区亚洲| 亚洲黄色影院| 午夜精品久久久久久久99水蜜桃 | 欧美mv日韩mv国产网站app| 亚洲欧美日韩国产中文| 美女露胸一区二区三区| 亚洲欧洲av一区二区| 免费日韩成人| 久久精品日韩| 国产精品久久久久久久久免费桃花 | 亚洲激情电影在线| 亚洲综合欧美| 中文欧美日韩| 美腿丝袜亚洲色图| 久久久久青草大香线综合精品| 欧美日韩伦理在线| 欧美高清视频一二三区| 国产一区二区三区的电影 | 黄色日韩网站视频| 亚洲一区二区高清视频| 一区二区三区久久网| 免费不卡在线观看| 麻豆精品视频| 国产日韩精品一区二区三区| 一本久道久久综合中文字幕| 日韩视频在线免费| 欧美国产日韩a欧美在线观看| 另类图片国产| 久久精品99国产精品日本| 亚洲视频一区在线观看| 欧美精品色一区二区三区| 亚洲国产精品精华液2区45| 影音先锋日韩精品| 久久电影一区| 久久亚洲综合| 一区二区在线不卡| 久久久精品2019中文字幕神马| 久久精品视频在线免费观看| 国产毛片久久| 久久国产精品一区二区三区| 久久久成人网| 好吊视频一区二区三区四区| 欧美一区二区三区免费观看| 久久不射网站| 国语自产精品视频在线看抢先版结局| 久久国产精品网站| 欧美国产日韩免费| 亚洲美女在线国产| 欧美午夜精品久久久久久孕妇| 亚洲午夜在线视频| 久久久精品五月天| 亚洲区欧美区| 欧美日韩一区国产| 小辣椒精品导航| 免费日韩av电影| 99pao成人国产永久免费视频| 欧美区国产区| 午夜精品久久一牛影视| 另类图片综合电影| 一区二区三区四区国产精品| 国产精品麻豆成人av电影艾秋| 欧美亚洲综合在线| 免费在线播放第一区高清av| 日韩亚洲欧美一区| 国产九区一区在线| 美女免费视频一区| 亚洲欧美日韩国产成人| 欧美成人四级电影| 亚洲一区日韩| 影音先锋亚洲电影| 欧美特黄一区| 久久久99久久精品女同性| 亚洲国内高清视频| 午夜精品久久久久久久久久久久 | 亚洲一区二区三区中文字幕| 老司机精品视频网站| 一区二区欧美激情| 国产综合欧美| 欧美午夜精品理论片a级大开眼界 欧美午夜精品理论片a级按摩 | 久久久亚洲国产美女国产盗摄| 亚洲国产精品一区二区www在线| 亚洲欧美激情精品一区二区| 亚洲国产综合91精品麻豆| 国产精品午夜视频| 欧美另类高清视频在线| 久久精品国产第一区二区三区最新章节 | 亚洲欧美成人网| 亚洲国产高清自拍| 狠狠狠色丁香婷婷综合久久五月 | 美女脱光内衣内裤视频久久网站| 亚洲另类在线一区| 国产真实久久| 欧美网站在线观看| 美日韩丰满少妇在线观看| 亚洲制服少妇| 亚洲最新视频在线| 亚洲国产日日夜夜| 欧美成人免费视频| 久久一区精品| 久久精品视频播放| 欧美亚洲日本国产|