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

來(lái)吧,朋友!

為C++瘋狂

如何使用CppUnit進(jìn)行單元測(cè)試

一、前言

  測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(TDD)是以測(cè)試作為開(kāi)發(fā)過(guò)程的中心,它堅(jiān)持,在編寫(xiě)實(shí)際代碼之前,先寫(xiě)好基于產(chǎn)品代碼的測(cè)試代碼。開(kāi)發(fā)過(guò)程的目標(biāo)就是首先使測(cè)試能夠通過(guò),然后再優(yōu)化設(shè)計(jì)結(jié)構(gòu)。測(cè)試驅(qū)動(dòng)開(kāi)發(fā)式是極限編程的重要組成部分。XUnit,一個(gè)基于測(cè)試驅(qū)動(dòng)開(kāi)發(fā)的測(cè)試框架,它為我們?cè)陂_(kāi)發(fā)過(guò)程中使用測(cè)試驅(qū)動(dòng)開(kāi)發(fā)提供了一個(gè)方便的工具,使我們得以快速的進(jìn)行單元測(cè)試。XUnit的成員有很多,如JUnit,PythonUnit等。今天給大家介紹的CppUnit即是XUnit家族中的一員,它是一個(gè)專(zhuān)門(mén)面向C++的測(cè)試框架。

本文不對(duì)CppUnit源碼做詳細(xì)的介紹,而只是對(duì)CppUnit的應(yīng)用作一些介紹。你將看到:

  1. CppUnit源代碼的各個(gè)組成部分;
  2. 怎樣設(shè)置你的開(kāi)發(fā)環(huán)境以能夠使用CppUnit;
  3. 怎樣為你的產(chǎn)品代碼添加測(cè)試代碼(實(shí)際上應(yīng)該反過(guò)來(lái),為測(cè)試代碼添加產(chǎn)品代碼。在TDD中,先有測(cè)試代碼后有產(chǎn)品代碼),并通過(guò)CppUnit來(lái)進(jìn)行測(cè)試;

本文敘述背景為:CppUnit1.12.0, Visual C++ 6.0, WindowsXP。文中敘述有誤之處,敬請(qǐng)批評(píng)指正。

一. CppUnit的安裝
從http://sourceforge.net/projects/cppunit CppUnit的源碼包. CppUnit是開(kāi)源產(chǎn)品 , 當(dāng)前最高版本為1.12.0. (在上面的鏈接所指向的頁(yè)面上選擇 Development Snapshot ).
下載后,將源碼包解壓縮到本地硬盤(pán),例如解壓到E:\ cppunit-1.12.0。筆者把文件夾名稱(chēng)中的版本號(hào)去掉,即源碼包解壓縮到E:\cppunit。下載解壓后,你將看到如下文件夾:

主要的文件夾有:

  • doc: CppUnit的說(shuō)明文檔。另外,代碼的根目錄,還有三個(gè)說(shuō)明文檔,分別是INSTALL,INSTALL-unix,INSTALL-WIN32.txt;
  • examples: CpppUnit提供的例子,也是對(duì)CppUnit自身的測(cè)試,通過(guò)它可以學(xué)習(xí)如何使用CppUnit測(cè)試框架進(jìn)行開(kāi)發(fā);
  • include: CppUnit頭文件;
  • src: CppUnit源代碼目錄;
  • config:配置文件;
  • contrib:contribution,其他人貢獻(xiàn)的外圍代碼;
  • lib:存放編譯好的庫(kù);
  • src:源文件,以及編譯庫(kù)的project等;

  接下來(lái)進(jìn)行編譯工作。 在src/目錄下, 將CppUnitLibraries.dsw工程文件用vc 打開(kāi)。執(zhí)行build/batch build,編譯成功的話(huà),生成的庫(kù)文件將被拷貝到lib目錄下。中途或者會(huì)有些project編譯失敗,一般不用管它,我們重點(diǎn)看的是cppunit和TestRunner 這兩個(gè)project的debug和release版本。
  編譯通過(guò)以后, 在lib/目錄下,會(huì)生成若干lib,和dll文件, 都以cppunit開(kāi)頭. cppunitd表示debug版, cppunit表示release版。
CppUnit為我們提供了兩套框架庫(kù),一個(gè)為靜態(tài)的lib,一個(gè)為動(dòng)態(tài)的dll。cppunit project:靜態(tài)lib;cppunit_dll project:動(dòng)態(tài)dll和lib。在開(kāi)發(fā)中我們可以根據(jù)實(shí)際情況作出選擇。
你也可以根據(jù)需要選擇所需的項(xiàng)目進(jìn)行編譯,其中項(xiàng)目cppunit為靜態(tài)庫(kù),cppunit_dll為動(dòng)態(tài)庫(kù),生成的庫(kù)文件為:

  • cppunit.lib:靜態(tài)庫(kù)release版;
  • cppunitd.lib:靜態(tài)庫(kù)debug版;
  • cppunit_dll.lib:動(dòng)態(tài)庫(kù)release版;
  • cppunitd_dll.lib:動(dòng)態(tài)庫(kù)debug版;

  另外一個(gè)需要關(guān)注的project是TestRunner,它輸出一個(gè)dll,提供了一個(gè)基于GUI 方式的測(cè)試環(huán)境,在CppUnit下, 可以選擇控制臺(tái)方式和GUI方式兩種表現(xiàn)方案。兩種方案分別如下圖所示:

我們選擇GUI方式,所以我們也需要編譯這個(gè)project,輸出位置亦為lib文件夾。
要使用CppUnit,還得設(shè)置好頭文件和庫(kù)文件路徑,以VC6為例,選擇Tools/Options/Directories,在Include files和Library files中分別添加%CppUnitPath%\include和%CppUnitPath%\lib,其中%CppUnitPath%表示CppUnit所在路徑。本文這里分別填的是E:\CPPUNIT\INCLUDE和E:\CPPUNIT\LIB。

二、概念

在使用之前,我們有必要認(rèn)識(shí)一下CppUnit中的主要類(lèi),當(dāng)然你也可以先看后面的例子,遇到問(wèn)題再回過(guò)頭來(lái)看這一節(jié)。
CppUnit核心內(nèi)容主要包括一些關(guān)鍵類(lèi):

Test:所有測(cè)試對(duì)象的基類(lèi)。

CppUnit采用樹(shù)形結(jié)構(gòu)來(lái)組織管理測(cè)試對(duì)象(類(lèi)似于目錄樹(shù),如下圖所示),因此這里采用了組合設(shè)計(jì)模式(Composite Pattern),Test的兩個(gè)直接子類(lèi)TestLeaf和TestComposite分別表示“測(cè)試樹(shù)”中的葉節(jié)點(diǎn)和非葉節(jié)點(diǎn),其中TestComposite主要起組織管理的作用,就像目錄樹(shù)中的文件夾,而TestLeaf才是最終具有執(zhí)行能力的測(cè)試對(duì)象,就像目錄樹(shù)中的文件。

Test最重要的一個(gè)公共接口為:

virtual void run(TestResult *result) = 0;

其作用為執(zhí)行測(cè)試對(duì)象,將結(jié)果提交給result。
在實(shí)際應(yīng)用中,我們一般不會(huì)直接使用Test、TestComposite以及TestLeaf,除非我們要重新定制某些機(jī)制。

TestFixture:用于維護(hù)一組測(cè)試用例的上下文環(huán)境。

  在實(shí)際應(yīng)用中,我們經(jīng)常會(huì)開(kāi)發(fā)一組測(cè)試用例來(lái)對(duì)某個(gè)類(lèi)的接口加以測(cè)試,而這些測(cè)試用例很可能具有相同的初始化和清理代碼。為此,CppUnit引入TestFixture來(lái)實(shí)現(xiàn)這一機(jī)制。
TestFixture具有以下兩個(gè)接口,分別用于處理測(cè)試環(huán)境的初始化與清理工作:

virtual void setUp();
virtual void tearDown();
TestCase:測(cè)試用例,從名字上就可以看出來(lái),它便是單元測(cè)試的執(zhí)行對(duì)象。

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

// 偽代碼
void TestCase::run(TestResult* result)
{
result->startTest(this); // 通知result測(cè)試開(kāi)始
if( result->protect(this, &TestCase::setUp) ) // 調(diào)用setUp,初始化環(huán)境
result->protect(this, &TestCase::runTest); // 執(zhí)行runTest,即真正的測(cè)試代碼
result->protect(this, &TestCase::tearDown); // 調(diào)用tearDown,清理環(huán)境
result->endTest(this); // 通知result測(cè)試結(jié)束
}
這里要提到的是函數(shù)runTest,它是TestCase定義的一個(gè)接口,原型如下:
virtual void runTest(); 

用戶(hù)需從TestCase派生出子類(lèi)并實(shí)現(xiàn)runTest以開(kāi)發(fā)自己所需的測(cè)試用例。
另外還要提到的就是TestResult的protect方法,其作用是對(duì)執(zhí)行函數(shù)(實(shí)際上是函數(shù)對(duì)象)的錯(cuò)誤信息(包括斷言和異常等)進(jìn)行捕獲,從而實(shí)現(xiàn)對(duì)測(cè)試結(jié)果的統(tǒng)計(jì)。

TestSuit:測(cè)試包,按照樹(shù)形結(jié)構(gòu)管理測(cè)試用例

TestSuit是TestComposite的一個(gè)實(shí)現(xiàn),它采用vector來(lái)管理子測(cè)試對(duì)象(Test),從而形成遞歸的樹(shù)形結(jié)構(gòu)。

TestFactory:測(cè)試工廠

這是一個(gè)輔助類(lèi),通過(guò)借助一系列宏定義讓測(cè)試用例的組織管理變得自動(dòng)化。參見(jiàn)后面的例子。

TestRunner:用于執(zhí)行測(cè)試用例

TestRunner將待執(zhí)行的測(cè)試對(duì)象管理起來(lái),然后供用戶(hù)調(diào)用。其接口為:

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

  這也是一個(gè)輔助類(lèi),需注意的是,通過(guò)addTest添加到TestRunner中的測(cè)試對(duì)象必須是通過(guò)new動(dòng)態(tài)創(chuàng)建的,用戶(hù)不能刪除這個(gè)對(duì)象,因?yàn)門(mén)estRunner將自行管理測(cè)試對(duì)象的生命期。

三、CppUnit 的使用

  以上工作完成以后,就可以正式使用CppUnit了,由于單元測(cè)試是TDD(測(cè)試驅(qū)動(dòng)開(kāi)發(fā))的利器,一般人會(huì)先寫(xiě)測(cè)試代碼,然后再寫(xiě)產(chǎn)品代碼,不過(guò)筆者認(rèn)為先寫(xiě)產(chǎn)品代碼框架后再寫(xiě)測(cè)試代碼,然后通過(guò)慢慢補(bǔ)充產(chǎn)品代碼以使得能通過(guò)測(cè)試的方法會(huì)好些。不管先寫(xiě)誰(shuí)只要寫(xiě)得舒服安全就可以。本文決定先寫(xiě)測(cè)試代碼。
  前面我們提到過(guò),CppUnit最小的測(cè)試單位是TestCase,多個(gè)相關(guān)TestCase組成一個(gè)TestSuite。要添加測(cè)試代碼最簡(jiǎn)單的方法就是利用CppUnit為我們提供的幾個(gè)宏來(lái)進(jìn)行(當(dāng)然還有其他的手工加入方法,但均是殊途同歸,大家可以查閱CppUnit頭文件中的演示代碼)。這幾個(gè)宏是:

CPPUNIT_TEST_SUITE() 開(kāi)始創(chuàng)建一個(gè)TestSuite;
CPPUNIT_TEST() 添加TestCase;
CPPUNIT_TEST_SUITE_END() 結(jié)束創(chuàng)建TestSuite;
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION() 添加一個(gè)TestSuite到一個(gè)指定的TestFactoryRegistry工廠。

感興趣的朋友可以在HelperMacros.h看看這幾個(gè)宏的聲明,本文在此不做詳述。
假定我們要實(shí)現(xiàn)一個(gè)類(lèi),類(lèi)名暫且取做CPlus,它的功能主要是實(shí)現(xiàn)兩個(gè)數(shù)相加(多簡(jiǎn)單的一個(gè)類(lèi)啊,這也要測(cè)試嗎?不要緊,我們只是了解怎樣加入測(cè)試代碼來(lái)測(cè)試它就行了,所以越簡(jiǎn)單越好)。 假定這個(gè)類(lèi)要實(shí)現(xiàn)的相加的方法是:

int Add(int nNum1, int nNum2);

  OK,那我們先來(lái)寫(xiě)測(cè)試這個(gè)方法的代碼吧。TDD 可是先寫(xiě)測(cè)試代碼,后寫(xiě)產(chǎn)品代碼(CPlus)的哦!先寫(xiě)的測(cè)試代碼往往是不能運(yùn)行或編譯的,我們的目標(biāo)是在寫(xiě)好測(cè)試代碼后寫(xiě)產(chǎn)品代碼,使之編譯通過(guò),然后再進(jìn)行重構(gòu)。這就是Kent Beck說(shuō)的“red/green/refactor”。所以,上面的類(lèi)名和方法應(yīng)該還只是在你的心里,還只是你的idea而已。
  根據(jù)測(cè)試驅(qū)動(dòng)的原理,我們需要先建立一個(gè)單元測(cè)試框架。我們?cè)赩C中為測(cè)試代碼建立一個(gè)project。通常,測(cè)試代碼和被測(cè)試對(duì)象(產(chǎn)品代碼)是處于不同的project中的。這樣就不會(huì)讓你的產(chǎn)品代碼被測(cè)試代碼所“污染 ”。
由于在CppUnit下, 可以選擇控制臺(tái)方式和UI方式兩種表現(xiàn)方案,我們選擇UI方式。在本例中,我們將建立一個(gè)基于GUI 方式的測(cè)試環(huán)境。因此我們建立一個(gè)基于對(duì)話(huà)框的Project。假設(shè)名為UnitTest。
建立了UnitTest project之后,我們首先配置這個(gè)工程。
首先在project中打開(kāi)RTTI開(kāi)關(guān),具體位置在菜單Project/Settings/C++/C++ Language。如下圖所示設(shè)置:

  由于CppUnit所用的動(dòng)態(tài)運(yùn)行期庫(kù)均為多線(xiàn)程動(dòng)態(tài)庫(kù),因此你的單元測(cè)試程序也得使用相應(yīng)設(shè)置,否則會(huì)發(fā)生沖突。于是我們?cè)赑roject/Settings/C++/Code Generation中進(jìn)行如下設(shè)置:
  在Use run-time library一欄中,針對(duì)debug和release分別設(shè)置為‘Debug Multithreaded DLL’和‘Multithreaded DLL’。如下圖所示:

  最后別忘了在project中l(wèi)ink正確的lib。包括本例采用的cppunit.lib和cppunitd.lib靜態(tài)庫(kù)以及用于GUI方式的TestRunner.dll對(duì)應(yīng)的lib。具體位置在Project/Settings/Link/General
  在‘Object/library modules’中,針對(duì)debug和release分別加入cppunitd.lib testrunnerd.lib和cppunit.lib TestRunner.lib。如下圖所示:

  最后,由于TestRunner.dll為我們提供了基于GUI的測(cè)試環(huán)境。為了讓我們的測(cè)試程序能正確的調(diào)用它,TestRunner.dll必須位于你的測(cè)試程序的路徑下。所以把/lib目錄下的testrunnerd.dll和TestRunner.dll文件分別拷貝到UnitTest priject的程序debug和release版本輸出目錄中。如下圖所示:

(這是release版本)只要放在一起就可以了。
配置工作終于完成,下面開(kāi)始寫(xiě)測(cè)試框架。

在CppUnit中, 是以TestCase為最小的測(cè)試單位, 若干TestCase組成一個(gè)TestSuite。所以我們要先建立一個(gè)TestCase。
在UnitTest project中新建一個(gè)類(lèi), 命名為CPlusTestCase, 讓其從CppUnit::TestCase派生。為其新增一個(gè)方法,假設(shè)為 void testAdd(); 我們將在這個(gè)函數(shù)中寫(xiě)入我們的一些測(cè)試代碼(還記得我們要測(cè)試的構(gòu)想中的CPlus::Add(…)嗎)。代碼如下:切記要包含頭文件

#include <cppunit/TestCase.h>
class CPlusTestCase : public CppUnit::TestCase
{
public:
CPlusTestCase ();
virtual ~ CPlusTestCase ();
void testAdd();
};
接下來(lái), 我們要對(duì)我們的CPlusTestCase進(jìn)行聲明。聲明用到了三個(gè)宏.
    CPPUNIT_TEST_SUITE();
CPPUNIT_TEST();
CPPUNIT_TEST_SUITE_END();
第一個(gè)宏聲明一個(gè)測(cè)試包(suite),第二個(gè)宏聲明(添加)一個(gè)測(cè)試用例. 現(xiàn)在我們的CPlusTestCase類(lèi)看上去象這樣:切記要包含頭文件,否則無(wú)法識(shí)別這些宏。
#include <cppunit/TestCase.h>
#include <CppUnit/extensions/HelperMacros.h>
class CPlusTestCase : public CppUnit::TestCase
{
CPPUNIT_TEST_SUITE(CPlusTestCase);
CPPUNIT_TEST(testAdd);
CPPUNIT_TEST_SUITE_END();
public:
CPlusTestCase ();
virtual ~ CPlusTestCase ();
void testAdd();
};
通過(guò)這幾個(gè)宏,我們就把CPlusTestCase和testAdd注冊(cè)到了測(cè)試列表當(dāng)中。

  接下來(lái),我們要注冊(cè)我們的測(cè)試suite. 使用CPPUNIT_TEST_SUITE_NAMED_REGISTRATION()來(lái)注冊(cè)一個(gè)測(cè)試suite. 這個(gè)宏的第二個(gè)參數(shù)是我們注冊(cè)的suite的名字. 在這里我們可以用字符串來(lái)代替, 但我們用一個(gè)靜態(tài)函數(shù)來(lái)返回這個(gè)suite的名字.

// PlusTestCase.h
class CPlusTestCase : public CppUnit::TestCase
{
CPPUNIT_TEST_SUITE(CPlusTestCase);
CPPUNIT_TEST(testAdd);
CPPUNIT_TEST_SUITE_END();
public:
CPlusTestCase ();
virtual ~ CPlusTestCase ();
void testAdd();
static std::string GetSuiteName();
};
// PlusTestCase.cpp
std::string CPlusTestCase::GetSuiteName()
{
return " CPlus ";
}
記得要在PlusTestCase.h中包含 #include <string>
然后在 PlusTestCase.cpp注冊(cè)我們的suite.
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CPlusTestCase, CPlusTestCase::GetSuiteName());

它將CPlusTestCase這個(gè)TestSuite注冊(cè)到一個(gè)指定的TestFactory工廠中。
接下來(lái)我們寫(xiě)一個(gè)注冊(cè)函數(shù)static CppUnit::Test* GetSuite(), 使其在運(yùn)行期生成一個(gè)Test.

// PlusTestCase.h
class CPlusTestCase : public CppUnit::TestCase
{
CPPUNIT_TEST_SUITE(CPlusTestCase);
CPPUNIT_TEST(testAdd);
CPPUNIT_TEST_SUITE_END();
public:
CPlusTestCase ();
virtual ~ CPlusTestCase ();
void testAdd();
static std::string GetSuiteName();
static CppUnit::Test* GetSuite();
};
// PlusTestCase.cpp
CppUnit::Test* CPlusTestCase::GetSuite()
{
CppUnit::TestFactoryRegistry& reg =
CppUnit::TestFactoryRegistry::getRegistry (CPlusTestCase::GetSuiteName());
return reg.makeTest();
}
記住在PlusTestCase.h中包含頭文件:
#include <cppunit/extensions/TestFactoryRegistry.h>
最后, 我們?yōu)閱卧獪y(cè)試建立一個(gè)UI測(cè)試界面.

  由于我們希望這個(gè)Project運(yùn)行后顯示的是GUI界面,所以我們需要在App的 InitInstance ()中屏蔽掉原有的對(duì)話(huà)框,代之以CppUnit的GUI。
我們?cè)贑UnitTestApp::InitInstance()函數(shù)中,將原先顯示主對(duì)話(huà)框的代碼以下面的代碼取代:

CppUnit::MfcUi::TestRunner runner;
runner.addTest(CPlusTestCase::GetSuite());//添加測(cè)試
runner.run();//show UI
/*	CUnitTestDlg 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
}
*/
切記必須先在UnitTest.cpp中包含頭文件:
#include <cppunit/ui/mfc/TestRunner.h>
#include " PlusTestCase.h "
到此為止, 我們已經(jīng)建立好一個(gè)簡(jiǎn)單的單元測(cè)試框架。測(cè)試框架雖然寫(xiě)好了,但是測(cè)試代碼仍然為空,產(chǎn)品代碼也還沒(méi)有寫(xiě)。下面我們來(lái)寫(xiě)測(cè)試代碼:
如前所述,在測(cè)試類(lèi)中,我們添加了一個(gè)測(cè)試方法:
void testAdd();
它測(cè)試的對(duì)象是前面提到的CPlus類(lèi)的方法:int Add(int nNum1, int nNum2);(產(chǎn)品代碼)我們來(lái)看看testAdd()的實(shí)現(xiàn):記得在PlusTestCase.h中包含頭文件
#include <cppunit/TestAssert.h>
// PlusTestCase.cpp
void CPlusTestCase::testAdd()
{
CPlus plus;
int nResult = plus.Add(10, 20); //執(zhí)行Add操作
CPPUNIT_ASSERT_EQUAL(30, nResult); //檢查結(jié)果是否等于30
}
CPPUNIT_ASSERT_EQUAL是一個(gè)判斷結(jié)果的宏。CppUnit中類(lèi)似的其它宏請(qǐng)查閱TestAssert.h,本文在此不做詳述 。

  另外,我們還可以覆寫(xiě)基類(lèi)的 setUp()、tearDown()兩個(gè)函數(shù)。這兩個(gè)函數(shù)實(shí)際上是一個(gè)模板方法,在測(cè)試運(yùn)行之前會(huì)調(diào)用setUp()以進(jìn)行一些初始化的工作,測(cè)試結(jié)束之后又會(huì)調(diào)用tearDown()來(lái)做一些“善后工作” ,比如資源的回收等等。當(dāng)然,你也可以不覆寫(xiě)這兩個(gè)函數(shù),因?yàn)樗鼈冊(cè)诨?lèi)里定義成了空方法,而不是純虛函數(shù)。
  編寫(xiě)完上面的測(cè)試代碼后,進(jìn)行編譯。編譯肯定通不過(guò),編譯器會(huì)告訴我們CPlus類(lèi)沒(méi)有聲明,因?yàn)槲覀冞€沒(méi)有實(shí)現(xiàn)CPlus類(lèi)呢!現(xiàn)在的工作就是馬上實(shí)現(xiàn)CPlus類(lèi),讓編譯通過(guò)。現(xiàn)在你應(yīng)該嗅到一點(diǎn)“測(cè)試驅(qū)動(dòng)”(Test Driven Develop)的味道了吧?

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

// Plus.h
class AFX_EXT_CLASS CPlus
{
public:
CPlus();
virtual ~CPlus();
public:
int Add(int nNum1, int nNum2);
};
Add在Plus.cpp中實(shí)現(xiàn)如下
int CPlus::Add(int nNum1, int nNum2)
{
return nNum1 + nNum2;//這里可以寫(xiě)一些錯(cuò)誤的語(yǔ)句,用來(lái)看看錯(cuò)誤的結(jié)果
}
非常簡(jiǎn)單,不是嗎?現(xiàn)在讓前面那個(gè)包含測(cè)試代碼的Project dependent這個(gè)Project,并且include 相關(guān)頭文件 ,Rebuild All,你會(huì)發(fā)現(xiàn)編譯已通過(guò)。你體會(huì)到了測(cè)試代碼驅(qū)動(dòng)產(chǎn)品代碼了嗎?當(dāng)然我們的這個(gè)例子還很簡(jiǎn)單 ,沒(méi)有重構(gòu)這一步驟。

運(yùn)行我們的測(cè)試程序,單擊Browse,你就會(huì)看到如下圖所示的界面:


選擇CPlusTestCase::testAdd后,單擊Run,你就會(huì)看到如下圖所示的界面:

  這下你應(yīng)該對(duì)前面我們說(shuō)的TestSuite的名字理解更深了吧。CPlus是一個(gè)測(cè)試包TestSuite,它的下面包含一個(gè)測(cè)試用例,這個(gè)測(cè)試用例下面又包含一個(gè)測(cè)試方法。

如果我修改CPlus::Add的代碼如下:

int CPlus::Add(int nNum1, int nNum2)
{
//	return nNum1 + nNum2;
return 2;
}
重新編譯通過(guò),運(yùn)行程序就會(huì)發(fā)現(xiàn):

GUI顯示有一個(gè)單元測(cè)試不通過(guò),并顯示出錯(cuò)的地方和原因,這樣就很好的控制Bug了。

四、下面是完整的程序清單

// PlusTestCase.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <string>
#include <cppunit/TestCase.h>
#include <CppUnit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/TestAssert.h>
class CPlusTestCase : public CppUnit::TestCase
{
//通過(guò)這幾個(gè)宏,我們就把CPlusTestCase和testAdd注冊(cè)到了測(cè)試列表當(dāng)中.
CPPUNIT_TEST_SUITE(CPlusTestCase);		//聲明一個(gè)測(cè)試包
CPPUNIT_TEST(testAdd);					//聲明一個(gè)測(cè)試用例
CPPUNIT_TEST_SUITE_END();
public:
CPlusTestCase();
virtual ~CPlusTestCase();
void testAdd(); //測(cè)試方法
static std::string GetSuiteName();
//寫(xiě)一個(gè)注冊(cè)函數(shù), 使其在運(yùn)行期生成一個(gè)Test
static CppUnit::Test* GetSuite();
};
// PlusTestCase.cpp
#include "stdafx.h"
#include "UnitTest.h"
#include "PlusTestCase.h"
#include "plus.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//注冊(cè)一個(gè)測(cè)試suite到一個(gè)指定的TestFactory工廠中
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CPlusTestCase, CPlusTestCase::GetSuiteName());
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CPlusTestCase::CPlusTestCase()
{
}
CPlusTestCase::~CPlusTestCase()
{
}
void CPlusTestCase::testAdd()
{
CPlus plus;
int nResult = plus.Add(10, 20); //執(zhí)行Add操作
CPPUNIT_ASSERT_EQUAL(30, nResult); //檢查結(jié)果是否等于30
}
std::string CPlusTestCase::GetSuiteName()
{
return "CPlus";
}
/*
*	注意:CPlusTestCase::GetSuite()返回一個(gè)指向CppUnit::Test的指針.
*  這個(gè)指針就是整個(gè)測(cè)試的起點(diǎn)。
*  CppUnit::TestFactoryRegistry::getRegistry()根據(jù)TestSuite的名字返回TestFactoryRegistry工
*  然后調(diào)用工廠里的makeTest()對(duì)TestSuite進(jìn)行組裝,將建立起一個(gè)樹(shù)狀的測(cè)試結(jié)構(gòu)。
*/
CppUnit::Test* CPlusTestCase::GetSuite()
{
CppUnit::TestFactoryRegistry& reg = CppUnit::TestFactoryRegistry::getRegistry(CPlusTestCase::GetSuiteName());
return reg.makeTest();
}
// UnitTest.cpp
#include "stdafx.h"
#include "UnitTest.h"
#include <cppunit/ui/mfc/TestRunner.h>
#include "PlusTestCase.h"
…
/////////////////////////////////////////////////////////////////////////////
// CUnitTestApp initialization
BOOL CUnitTestApp::InitInstance()
{
…
CppUnit::MfcUi::TestRunner runner;
runner.addTest(CPlusTestCase::GetSuite()); //添加測(cè)試	runner.addTest(CMinusTestCase::GetSuite());
runner.run(); //show UI
/*	CUnitTestDlg 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
}
*/
return FALSE;
}
五、參考資料
  • Cpluser《CppUnit測(cè)試框架入門(mén)》
  • Freefalcon《CppUnit快速入門(mén)》
  • 《使用CppUnit進(jìn)行單元測(cè)試》

posted on 2009-07-09 19:34 yanghaibao 閱讀(351) 評(píng)論(0)  編輯 收藏 引用

導(dǎo)航

<2025年12月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

統(tǒng)計(jì)

常用鏈接

留言簿

隨筆分類(lèi)

隨筆檔案

文章檔案

收藏夾

Good blogs

搜索

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲国产精品成人va在线观看| 亚洲人www| 欧美激情中文不卡| 国产日韩欧美自拍| 9久草视频在线视频精品| 亚洲经典自拍| 理论片一区二区在线| 久久久成人精品| 国产精品普通话对白| 日韩午夜在线视频| 日韩视频精品| 欧美国产国产综合| 欧美福利电影网| 在线国产亚洲欧美| 久久另类ts人妖一区二区| 性欧美xxxx大乳国产app| 欧美涩涩网站| 99精品福利视频| 亚洲午夜精品一区二区| 欧美日韩国产不卡在线看| 亚洲国产天堂久久综合网| 亚洲国产成人久久综合| 久久影视三级福利片| 看片网站欧美日韩| 尤物yw午夜国产精品视频明星| 你懂的国产精品永久在线| 国产亚洲精品一区二区| 久久国产精品久久久久久久久久| 韩国一区二区在线观看| 欧美永久精品| 免费久久久一本精品久久区| 激情小说另类小说亚洲欧美| 久久蜜臀精品av| 久久亚洲私人国产精品va| 国产一区二区久久精品| 久久久久久免费| 欧美黄色一区| 亚洲视频1区| 国产精品一区视频网站| 欧美一区二区视频在线观看2020| 欲香欲色天天天综合和网| 久久免费午夜影院| 亚洲激情欧美激情| 亚洲一区中文| 国产乱码精品一区二区三区五月婷 | 欧美天堂亚洲电影院在线播放| 亚洲婷婷免费| 国产欧美一区二区精品忘忧草| 美女免费视频一区| 亚洲欧洲一区二区在线播放| 欧美不卡一卡二卡免费版| 99re成人精品视频| 久久国产精品久久精品国产| 伊人成人开心激情综合网| 欧美国产日本在线| 亚洲伊人伊色伊影伊综合网| 免费日韩av片| 亚洲一区图片| 在线国产精品播放| 欧美午夜精品久久久久久浪潮| 亚洲第一精品影视| 亚洲欧美日韩国产综合精品二区| 欧美成人午夜剧场免费观看| 国产性做久久久久久| 久久成人免费视频| 91久久精品国产91性色| 久久av一区二区| 亚洲精选久久| 国产欧美一区二区精品性| 欧美成人精品三级在线观看| 亚洲综合电影一区二区三区| 欧美韩国日本综合| 欧美综合二区| 亚洲一级电影| 亚洲精品国产精品国自产观看浪潮 | 亚洲国产三级| 欧美一区二区免费| 亚洲激情视频| 国产综合色产在线精品| 欧美午夜精品久久久久久孕妇| 日韩一区二区精品| 欧美成人精品不卡视频在线观看| 亚洲欧洲精品一区二区三区波多野1战4 | 亚洲综合日韩中文字幕v在线| 亚洲人成网在线播放| 国产日韩欧美在线播放不卡| 欧美色欧美亚洲另类二区| 久久久水蜜桃| 亚洲欧美国产制服动漫| 日韩视频在线一区二区三区| 欧美成人免费视频| 久久综合久久久久88| 欧美中文字幕在线| 亚洲欧美国产三级| 一区二区三区四区五区视频| 亚洲日韩成人| 亚洲欧洲精品一区二区三区不卡 | 精品成人一区| 国产精品日本精品| 亚洲永久在线观看| 在线中文字幕一区| 在线视频欧美日韩精品| 亚洲免费观看在线视频| 亚洲精选一区| 日韩天堂在线观看| 在线视频欧美精品| 亚洲一区成人| 香蕉久久久久久久av网站| 亚洲综合国产| 欧美一区二区三区日韩视频| 香蕉成人啪国产精品视频综合网| 久久久久久久网| 久久嫩草精品久久久精品| 久久久久久久久蜜桃| 久久久噜噜噜久久中文字幕色伊伊| 亚洲成人在线免费| 亚洲国产精品久久久久婷婷884| 欧美噜噜久久久xxx| 欧美人与性禽动交情品| 欧美日韩一区二区高清| 国产精品高潮呻吟久久av无限| 久久激五月天综合精品| 久久久久99| 欧美成人精品高清在线播放| 欧美h视频在线| 欧美日本一区二区三区| 国产精品免费一区二区三区在线观看| 久久久999精品免费| 免费一级欧美片在线播放| 欧美精品在线视频观看| 国产精品免费一区豆花| 国产欧美亚洲精品| 亚洲国产美女久久久久| 中文精品99久久国产香蕉| 亚洲欧美中文另类| 美女脱光内衣内裤视频久久影院| 销魂美女一区二区三区视频在线| 1024欧美极品| 亚洲视频免费看| 久久国产天堂福利天堂| 蜜臀99久久精品久久久久久软件| 欧美亚洲免费| 欧美激情亚洲综合一区| 一本综合精品| 久久亚洲午夜电影| 国产精品久久婷婷六月丁香| 一区免费在线| 午夜国产精品影院在线观看| 久热精品视频在线观看| 日韩视频免费观看高清完整版| 久久午夜精品一区二区| 亚洲大胆av| 亚洲视频一区二区在线观看| 久久久国产精彩视频美女艺术照福利 | 国产亚洲福利| 亚洲人成在线播放网站岛国| 亚洲女人天堂av| 欧美国产在线观看| 午夜亚洲视频| 国产精品国产三级国产aⅴ浪潮 | 欧美在线播放一区二区| 亚洲高清免费视频| 欧美在线免费一级片| 国产精品swag| 日韩午夜电影av| 欧美插天视频在线播放| 中文日韩在线视频| 欧美精品午夜视频| 亚洲国产二区| 久久久久久欧美| 亚洲愉拍自拍另类高清精品| 欧美精品一区二区三区久久久竹菊| 欧美激情一区二区| 在线观看三级视频欧美| 久久精品亚洲一区二区| 在线亚洲一区| 欧美精品三级| 亚洲精品中文字幕有码专区| 麻豆精品精华液| 久久av在线看| 黄色成人av网站| 久久蜜桃香蕉精品一区二区三区| 久久久免费精品视频| 亚洲一区免费观看| 国产精品美女在线观看| 亚洲影视九九影院在线观看| 日韩一级裸体免费视频| 欧美日本一道本| 亚洲视频免费在线观看| 亚洲精选91| 欧美涩涩视频| 香蕉久久一区二区不卡无毒影院 | 欧美在线观看一二区| 日韩视频第一页| 欧美日韩一区二区在线观看视频| 国产日韩一区二区| 久久久精品动漫| 久久久亚洲高清| 亚洲国产另类 国产精品国产免费| 一本色道88久久加勒比精品|