C++程序的单元测试
生活随笔
收集整理的這篇文章主要介紹了
C++程序的单元测试
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
測(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è)專門面向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.9.0, Visual C++ 6.0, Windows2000。文中敘述有誤之處,敬請(qǐng)批評(píng)指正。?
一、CppUnit源碼組成?
CppUnit測(cè)試框架的源代碼可以到?[url]http://sourceforge.net/projects/cppunit/[/url]?上下載。下載解壓后,主要的文件夾有:?
????? 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源代碼目錄。?
二、初識(shí)CppUnit測(cè)試環(huán)境?
解壓源代碼包后,您一定急著想看看CppUnit到底是個(gè)什么樣?Ok,下面我們就來(lái)揭開(kāi)CppUnit的神秘面紗:
1、進(jìn)入example文件夾,用VC打開(kāi)examples.dsw。我們先來(lái)看看CppUnit自帶的測(cè)試?yán)印_@些例子都是針對(duì)CppUnit自身的單元測(cè)試集,一方面這是CppUnit作者開(kāi)發(fā)CppUnit框架過(guò)程中寫(xiě)的測(cè)試用例,另一方面,我們可以通過(guò)這些例子來(lái)學(xué)習(xí)如何在我們自己的工程中添加測(cè)試用例。
2、將CppUnitTestApp工程設(shè)為Active Project(Win32 Debug),編譯后運(yùn)行,則可以看到CppUnit的基于GUI方式進(jìn)行單元測(cè)試TestRunner的界面。點(diǎn)擊“Run”,?
這是一個(gè)針對(duì)CppUnit的單元測(cè)試結(jié)果,它表明剛才我們做了11個(gè)測(cè)試,全部通過(guò)。?
點(diǎn)擊“Browse”,我們還可以選擇想要進(jìn)行的單元測(cè)試
CppUnit將所有的單元測(cè)試按照樹(shù)的結(jié)構(gòu)來(lái)表示。在CppUnit中,最小的測(cè)試單元,稱為TestMethod測(cè)試方法,而多個(gè)相關(guān)的測(cè)試方法又可以組成一個(gè)TestCase測(cè)試用例。多個(gè)測(cè)試用例又組成TestSuite測(cè)試包。測(cè)試包互相嵌套在一起,就形成了上面我們看到的樹(shù)結(jié)構(gòu)。我們可以選擇其中任意的樹(shù)節(jié)點(diǎn)來(lái)進(jìn)行單元測(cè)試。?
3、將CppUnitTestMain工程設(shè)置為Active Project(Win32 Debug),編譯并運(yùn)行,我們來(lái)看看另一個(gè)單元測(cè)試的環(huán)境
這是一個(gè)基于文本方式的單元測(cè)試環(huán)境。CppUnit提供了幾種測(cè)試環(huán)境,一種基于文本,一種基于GUI,?
4、將HostApp工程設(shè)置為Active Project(Win32 Debug),編譯運(yùn)行。
這亦是一個(gè)對(duì)CppUnit自身進(jìn)行的測(cè)試,只不過(guò)它向我們演示的是各種失敗的測(cè)試。在基于GUI的測(cè)試環(huán)境中,若測(cè)試不成功,進(jìn)度條顯示紅色,反之則為綠色。從測(cè)試結(jié)果我們可以看到失敗的單元測(cè)試名稱,引起測(cè)試不能通過(guò)的原因,以及測(cè)試失敗的語(yǔ)句所在的文件及所在行數(shù)。?
三、CppUnit開(kāi)發(fā)環(huán)境設(shè)置?
認(rèn)識(shí)了CppUnit的測(cè)試環(huán)境,想必你已經(jīng)是在磨拳擦掌,準(zhǔn)備在你的開(kāi)發(fā)過(guò)程中感受一下測(cè)試驅(qū)動(dòng)開(kāi)發(fā)的感覺(jué)了。不過(guò),在使用CppUnit前,還需要設(shè)置一下你的開(kāi)發(fā)環(huán)境。?
1、CppUnit的lib和dll?
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ìn)入src文件夾,打開(kāi)CppUnitLibraries.dsw。分別編譯這兩個(gè)project,輸出位置均為lib文件夾。?
另外一個(gè)需要關(guān)注的project是TestRunner,它輸出一個(gè)dll,提供了一個(gè)基于GUI 方式的測(cè)試環(huán)境,即前面我們提到的兩種測(cè)試環(huán)境之一。我們也需要編譯這個(gè)project,輸出位置亦為lib文件夾。?
為了方便開(kāi)發(fā),我們把這些編譯出來(lái)的lib和dll(包括Debug版和Release版) copy 到我們自己建立的一個(gè)文件夾中(當(dāng)然你也可以不這么做),例如F:\cppunit1.9.0\lib\,同時(shí)我們也把CppUnit源代碼中include文件夾copy到我們自己的include文件夾下。然后在VC的tools/options/directories/include files和library files中設(shè)置include路徑和lib路徑。最后別忘了在你的project中l(wèi)ink正確的lib。?
2、在你的VC project中打開(kāi)RTTI開(kāi)關(guān)。?
具體位置Project Settings/C++/C++ Language。?
3、為TestRunner.dll設(shè)置環(huán)境變量?
TestRunner.dll為我們提供了基于GUI的測(cè)試環(huán)境。為了讓我們的測(cè)試程序能正確的調(diào)用它,TestRunner.dll必須位于你的測(cè)試程序的路徑下。但最簡(jiǎn)單的方法是在操作系統(tǒng)的環(huán)境變量Path中添TestRunner.dll的路徑,這樣是最省事的。?
四、你的第一個(gè)TDD example?
一切準(zhǔn)備就緒,現(xiàn)在我們可以來(lái)看看怎樣添加測(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è)宏的聲明,本文在此不做詳述。?
1、一個(gè)實(shí)現(xiàn)兩個(gè)整數(shù)相加的類?
假定我們要實(shí)現(xiàn)一個(gè)類,類名暫且取做CPlus,它的功能主要是實(shí)現(xiàn)兩個(gè)數(shù)相加(多簡(jiǎn)單的一個(gè)類啊,這也要測(cè)試嗎?不要緊,我們只是了解怎樣加入測(cè)試代碼來(lái)測(cè)試它就行了,所以越簡(jiǎn)單越好)。 假定這個(gè)類要實(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”( 還記得基于GUI的測(cè)試環(huán)境的狀態(tài)條嗎?)。所以,上面的類名和方法應(yīng)該還只是在你的心里,還只是你的idea而已。?
2、在VC中為測(cè)試代碼建立一個(gè) Project?
通常,測(cè)試代碼和被測(cè)試對(duì)象是處于不同的Project中的。這樣就不會(huì)讓你的產(chǎn)品代碼被測(cè)試代碼所“污染 ”。?
在本例中,我們將建立一個(gè)基于GUI 方式的測(cè)試環(huán)境。在VC中,我們建立一個(gè)基于對(duì)話框的Project。別忘了link正確的lib,本例中我們使用靜態(tài)的CppUnit lib。由于我們希望這個(gè)Project運(yùn)行后顯示的是圖2這樣的界面,所以我們需要在App的 Instance()中屏蔽掉原有的對(duì)話框,代之以CppUnit的GUI。?
CppUnit::MfcUi::TestRunner runner;
runner.addTest(PlusTest::suite()); //添加測(cè)試
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
}
*/
前面我們提到過(guò),TestRunner輸出圖2這樣的對(duì)話框,這也是前面我們?yōu)槭裁匆獮門estRunner.dll的路徑設(shè)置環(huán)境變量的原因。?
注意:PlusTest::suite()返回一個(gè)指向CppUnit::Test的指針.這個(gè)指針就是整個(gè)測(cè)試的起點(diǎn)。CppUnit::TestFactoryRegistry::getRegistry()根據(jù)TestSuite的名字返回TestFactoryRegistry工廠,然后調(diào)用工廠里的makeTest()對(duì)TestSuite進(jìn)行組裝,這是個(gè)遞歸調(diào)用,將建立起一個(gè)樹(shù)狀的測(cè)試結(jié)構(gòu)。?
namespace PlusTest
{??????CppUnit::Test* suite()
?????? {?????? CppUnit::TestFactoryRegistry ?istry =?
???????????????????? CppUnit::TestFactoryRegistry::getRegistry(plusSuiteName());
??????????????return registry.makeTest(); }}
另外別忘加頭文件:?
#include "CPlusTestSuite.h"
#include??
#include??
3、在Project中加入一個(gè)類,取名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(); //測(cè)試方法};?
看到這幾個(gè)宏了嗎?它們可是在這大顯身手了一把。?
CPPUNIT_TEST_SUITE(CPlusTestCase);?
CPPUNIT_TEST( testAdd );?
CPPUNIT_TEST_SUITE_END();?
通過(guò)這幾個(gè)宏,我們就把CPlusTestCase和testAdd注冊(cè)到了測(cè)試列表當(dāng)中。?
另外,我們需要在Cpp文件中加入另外一個(gè)宏:?
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CPlusTestCase,PlusTest::plusSuiteName() );?
它將CPlusTestCase這個(gè)TestSuite注冊(cè)到一個(gè)指定的TestFactory工廠中,這個(gè)TestSuite用 PlusTest::plusSuiteName()函數(shù)返回的名字來(lái)標(biāo)識(shí)(前面介紹的suite()函數(shù)中就是通過(guò)這個(gè)名字來(lái)獲取這個(gè)工廠的)。plusSuiteName()是PlusTest這個(gè)namespace下的一個(gè)函數(shù),它返回我們?yōu)檫@個(gè)TestSuite建立的名字(本例我們?nèi)∶麨椤皃lus”)。其實(shí)我們也可以不用這么做,直接在宏里寫(xiě)入“plus“即可。但是這樣可以防止硬編碼帶來(lái)的麻煩。?
在測(cè)試類中,我們添加了一個(gè)測(cè)試方法:?
void testAdd();?
它測(cè)試的對(duì)象是前面提到的CPlus類的方法:
int Add(int nNum1, int nNum2);?
我們來(lái)看看它的實(shí)現(xiàn):?
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中類似的其它宏請(qǐng)查閱TestAssert.h,本文在此不做詳述 。?
另外,我們還可以覆寫(xiě)基類的 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è)诨惱锒x成了空方法,而不是純虛函數(shù)。另外,Cpp中要加入頭文件:?
#include "plusSuite.h"?
4、根據(jù)測(cè)試代碼編寫(xiě)產(chǎn)品代碼?
編寫(xiě)完上面的測(cè)試代碼后,進(jìn)行編譯。編譯肯定通不過(guò),編譯器會(huì)告訴我們CPlus類沒(méi)有聲明,因?yàn)槲覀冞€沒(méi)有實(shí)現(xiàn)CPlus類呢!現(xiàn)在的工作就是馬上實(shí)現(xiàn)CPlus類,讓編譯通過(guò)。現(xiàn)在你應(yīng)該嗅到一點(diǎn)“測(cè)試驅(qū)動(dòng)“的味道了吧??
在VC中建立一個(gè)MFC Extension Dll的Project,在這個(gè)Project 中加入類CPlus,它的聲明如下:?
class AFX_EXT_CLASS CPlus
{public:
?????? CPlus();
?????? virtual ~CPlus(); public:
?????? int Add(int nNum1, int nNum2);};????????
僅有一個(gè)方法,就是我們的測(cè)試代碼要測(cè)試的那個(gè)方法。來(lái)看看它的實(shí)現(xiàn):?
int CPlus::Add(int nNum1, int nNum2)
{return nNum1+nNum2;}?
非常簡(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è)試程序,你就會(huì)看到界面:
單擊”Browse”,
這下你應(yīng)該對(duì)前面我們說(shuō)的TestSuite的名字理解更深了吧。plus是一個(gè)測(cè)試包TestSuite,它的下面包含一個(gè)測(cè)試用例,這個(gè)測(cè)試用例下面又包含一個(gè)測(cè)試方法。?
至此,我們對(duì)CppUnit測(cè)試框架的應(yīng)用作了一個(gè)詳細(xì)的介紹,希望能對(duì)你在進(jìn)行TDD過(guò)程中有所幫助。
本文轉(zhuǎn)自 fish_yy 51CTO博客,原文鏈接:http://blog.51cto.com/tester2test/137293,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
本文不對(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.9.0, Visual C++ 6.0, Windows2000。文中敘述有誤之處,敬請(qǐng)批評(píng)指正。?
一、CppUnit源碼組成?
CppUnit測(cè)試框架的源代碼可以到?[url]http://sourceforge.net/projects/cppunit/[/url]?上下載。下載解壓后,主要的文件夾有:?
????? 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源代碼目錄。?
二、初識(shí)CppUnit測(cè)試環(huán)境?
解壓源代碼包后,您一定急著想看看CppUnit到底是個(gè)什么樣?Ok,下面我們就來(lái)揭開(kāi)CppUnit的神秘面紗:
1、進(jìn)入example文件夾,用VC打開(kāi)examples.dsw。我們先來(lái)看看CppUnit自帶的測(cè)試?yán)印_@些例子都是針對(duì)CppUnit自身的單元測(cè)試集,一方面這是CppUnit作者開(kāi)發(fā)CppUnit框架過(guò)程中寫(xiě)的測(cè)試用例,另一方面,我們可以通過(guò)這些例子來(lái)學(xué)習(xí)如何在我們自己的工程中添加測(cè)試用例。
2、將CppUnitTestApp工程設(shè)為Active Project(Win32 Debug),編譯后運(yùn)行,則可以看到CppUnit的基于GUI方式進(jìn)行單元測(cè)試TestRunner的界面。點(diǎn)擊“Run”,?
這是一個(gè)針對(duì)CppUnit的單元測(cè)試結(jié)果,它表明剛才我們做了11個(gè)測(cè)試,全部通過(guò)。?
點(diǎn)擊“Browse”,我們還可以選擇想要進(jìn)行的單元測(cè)試
CppUnit將所有的單元測(cè)試按照樹(shù)的結(jié)構(gòu)來(lái)表示。在CppUnit中,最小的測(cè)試單元,稱為TestMethod測(cè)試方法,而多個(gè)相關(guān)的測(cè)試方法又可以組成一個(gè)TestCase測(cè)試用例。多個(gè)測(cè)試用例又組成TestSuite測(cè)試包。測(cè)試包互相嵌套在一起,就形成了上面我們看到的樹(shù)結(jié)構(gòu)。我們可以選擇其中任意的樹(shù)節(jié)點(diǎn)來(lái)進(jìn)行單元測(cè)試。?
3、將CppUnitTestMain工程設(shè)置為Active Project(Win32 Debug),編譯并運(yùn)行,我們來(lái)看看另一個(gè)單元測(cè)試的環(huán)境
這是一個(gè)基于文本方式的單元測(cè)試環(huán)境。CppUnit提供了幾種測(cè)試環(huán)境,一種基于文本,一種基于GUI,?
4、將HostApp工程設(shè)置為Active Project(Win32 Debug),編譯運(yùn)行。
這亦是一個(gè)對(duì)CppUnit自身進(jìn)行的測(cè)試,只不過(guò)它向我們演示的是各種失敗的測(cè)試。在基于GUI的測(cè)試環(huán)境中,若測(cè)試不成功,進(jìn)度條顯示紅色,反之則為綠色。從測(cè)試結(jié)果我們可以看到失敗的單元測(cè)試名稱,引起測(cè)試不能通過(guò)的原因,以及測(cè)試失敗的語(yǔ)句所在的文件及所在行數(shù)。?
三、CppUnit開(kāi)發(fā)環(huán)境設(shè)置?
認(rèn)識(shí)了CppUnit的測(cè)試環(huán)境,想必你已經(jīng)是在磨拳擦掌,準(zhǔn)備在你的開(kāi)發(fā)過(guò)程中感受一下測(cè)試驅(qū)動(dòng)開(kāi)發(fā)的感覺(jué)了。不過(guò),在使用CppUnit前,還需要設(shè)置一下你的開(kāi)發(fā)環(huán)境。?
1、CppUnit的lib和dll?
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ìn)入src文件夾,打開(kāi)CppUnitLibraries.dsw。分別編譯這兩個(gè)project,輸出位置均為lib文件夾。?
另外一個(gè)需要關(guān)注的project是TestRunner,它輸出一個(gè)dll,提供了一個(gè)基于GUI 方式的測(cè)試環(huán)境,即前面我們提到的兩種測(cè)試環(huán)境之一。我們也需要編譯這個(gè)project,輸出位置亦為lib文件夾。?
為了方便開(kāi)發(fā),我們把這些編譯出來(lái)的lib和dll(包括Debug版和Release版) copy 到我們自己建立的一個(gè)文件夾中(當(dāng)然你也可以不這么做),例如F:\cppunit1.9.0\lib\,同時(shí)我們也把CppUnit源代碼中include文件夾copy到我們自己的include文件夾下。然后在VC的tools/options/directories/include files和library files中設(shè)置include路徑和lib路徑。最后別忘了在你的project中l(wèi)ink正確的lib。?
2、在你的VC project中打開(kāi)RTTI開(kāi)關(guān)。?
具體位置Project Settings/C++/C++ Language。?
3、為TestRunner.dll設(shè)置環(huán)境變量?
TestRunner.dll為我們提供了基于GUI的測(cè)試環(huán)境。為了讓我們的測(cè)試程序能正確的調(diào)用它,TestRunner.dll必須位于你的測(cè)試程序的路徑下。但最簡(jiǎn)單的方法是在操作系統(tǒng)的環(huán)境變量Path中添TestRunner.dll的路徑,這樣是最省事的。?
四、你的第一個(gè)TDD example?
一切準(zhǔn)備就緒,現(xiàn)在我們可以來(lái)看看怎樣添加測(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è)宏的聲明,本文在此不做詳述。?
1、一個(gè)實(shí)現(xiàn)兩個(gè)整數(shù)相加的類?
假定我們要實(shí)現(xiàn)一個(gè)類,類名暫且取做CPlus,它的功能主要是實(shí)現(xiàn)兩個(gè)數(shù)相加(多簡(jiǎn)單的一個(gè)類啊,這也要測(cè)試嗎?不要緊,我們只是了解怎樣加入測(cè)試代碼來(lái)測(cè)試它就行了,所以越簡(jiǎn)單越好)。 假定這個(gè)類要實(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”( 還記得基于GUI的測(cè)試環(huán)境的狀態(tài)條嗎?)。所以,上面的類名和方法應(yīng)該還只是在你的心里,還只是你的idea而已。?
2、在VC中為測(cè)試代碼建立一個(gè) Project?
通常,測(cè)試代碼和被測(cè)試對(duì)象是處于不同的Project中的。這樣就不會(huì)讓你的產(chǎn)品代碼被測(cè)試代碼所“污染 ”。?
在本例中,我們將建立一個(gè)基于GUI 方式的測(cè)試環(huán)境。在VC中,我們建立一個(gè)基于對(duì)話框的Project。別忘了link正確的lib,本例中我們使用靜態(tài)的CppUnit lib。由于我們希望這個(gè)Project運(yùn)行后顯示的是圖2這樣的界面,所以我們需要在App的 Instance()中屏蔽掉原有的對(duì)話框,代之以CppUnit的GUI。?
CppUnit::MfcUi::TestRunner runner;
runner.addTest(PlusTest::suite()); //添加測(cè)試
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
}
*/
前面我們提到過(guò),TestRunner輸出圖2這樣的對(duì)話框,這也是前面我們?yōu)槭裁匆獮門estRunner.dll的路徑設(shè)置環(huán)境變量的原因。?
注意:PlusTest::suite()返回一個(gè)指向CppUnit::Test的指針.這個(gè)指針就是整個(gè)測(cè)試的起點(diǎn)。CppUnit::TestFactoryRegistry::getRegistry()根據(jù)TestSuite的名字返回TestFactoryRegistry工廠,然后調(diào)用工廠里的makeTest()對(duì)TestSuite進(jìn)行組裝,這是個(gè)遞歸調(diào)用,將建立起一個(gè)樹(shù)狀的測(cè)試結(jié)構(gòu)。?
namespace PlusTest
{??????CppUnit::Test* suite()
?????? {?????? CppUnit::TestFactoryRegistry ?istry =?
???????????????????? CppUnit::TestFactoryRegistry::getRegistry(plusSuiteName());
??????????????return registry.makeTest(); }}
另外別忘加頭文件:?
#include "CPlusTestSuite.h"
#include??
#include??
3、在Project中加入一個(gè)類,取名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(); //測(cè)試方法};?
看到這幾個(gè)宏了嗎?它們可是在這大顯身手了一把。?
CPPUNIT_TEST_SUITE(CPlusTestCase);?
CPPUNIT_TEST( testAdd );?
CPPUNIT_TEST_SUITE_END();?
通過(guò)這幾個(gè)宏,我們就把CPlusTestCase和testAdd注冊(cè)到了測(cè)試列表當(dāng)中。?
另外,我們需要在Cpp文件中加入另外一個(gè)宏:?
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CPlusTestCase,PlusTest::plusSuiteName() );?
它將CPlusTestCase這個(gè)TestSuite注冊(cè)到一個(gè)指定的TestFactory工廠中,這個(gè)TestSuite用 PlusTest::plusSuiteName()函數(shù)返回的名字來(lái)標(biāo)識(shí)(前面介紹的suite()函數(shù)中就是通過(guò)這個(gè)名字來(lái)獲取這個(gè)工廠的)。plusSuiteName()是PlusTest這個(gè)namespace下的一個(gè)函數(shù),它返回我們?yōu)檫@個(gè)TestSuite建立的名字(本例我們?nèi)∶麨椤皃lus”)。其實(shí)我們也可以不用這么做,直接在宏里寫(xiě)入“plus“即可。但是這樣可以防止硬編碼帶來(lái)的麻煩。?
在測(cè)試類中,我們添加了一個(gè)測(cè)試方法:?
void testAdd();?
它測(cè)試的對(duì)象是前面提到的CPlus類的方法:
int Add(int nNum1, int nNum2);?
我們來(lái)看看它的實(shí)現(xiàn):?
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中類似的其它宏請(qǐng)查閱TestAssert.h,本文在此不做詳述 。?
另外,我們還可以覆寫(xiě)基類的 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è)诨惱锒x成了空方法,而不是純虛函數(shù)。另外,Cpp中要加入頭文件:?
#include "plusSuite.h"?
4、根據(jù)測(cè)試代碼編寫(xiě)產(chǎn)品代碼?
編寫(xiě)完上面的測(cè)試代碼后,進(jìn)行編譯。編譯肯定通不過(guò),編譯器會(huì)告訴我們CPlus類沒(méi)有聲明,因?yàn)槲覀冞€沒(méi)有實(shí)現(xiàn)CPlus類呢!現(xiàn)在的工作就是馬上實(shí)現(xiàn)CPlus類,讓編譯通過(guò)。現(xiàn)在你應(yīng)該嗅到一點(diǎn)“測(cè)試驅(qū)動(dòng)“的味道了吧??
在VC中建立一個(gè)MFC Extension Dll的Project,在這個(gè)Project 中加入類CPlus,它的聲明如下:?
class AFX_EXT_CLASS CPlus
{public:
?????? CPlus();
?????? virtual ~CPlus(); public:
?????? int Add(int nNum1, int nNum2);};????????
僅有一個(gè)方法,就是我們的測(cè)試代碼要測(cè)試的那個(gè)方法。來(lái)看看它的實(shí)現(xiàn):?
int CPlus::Add(int nNum1, int nNum2)
{return nNum1+nNum2;}?
非常簡(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è)試程序,你就會(huì)看到界面:
單擊”Browse”,
這下你應(yīng)該對(duì)前面我們說(shuō)的TestSuite的名字理解更深了吧。plus是一個(gè)測(cè)試包TestSuite,它的下面包含一個(gè)測(cè)試用例,這個(gè)測(cè)試用例下面又包含一個(gè)測(cè)試方法。?
至此,我們對(duì)CppUnit測(cè)試框架的應(yīng)用作了一個(gè)詳細(xì)的介紹,希望能對(duì)你在進(jìn)行TDD過(guò)程中有所幫助。
本文轉(zhuǎn)自 fish_yy 51CTO博客,原文鏈接:http://blog.51cto.com/tester2test/137293,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔為你收集整理的C++程序的单元测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: VUE搭建开发,以及打包。
- 下一篇: iphone:MKMapView