一個(gè)高效的軟件開(kāi)發(fā)過(guò)程對軟件開(kāi)發(fā)人員來(lái)說(shuō)是至關(guān)重要的,決定著(zhù)開(kāi)發(fā)是痛苦的掙扎,還是不斷進(jìn)步的喜悅。國人對軟件藍領(lǐng)的不屑,對繁瑣冗長(cháng)的傳統開(kāi)發(fā)過(guò)程的不耐,使大多數開(kāi)發(fā)人員無(wú)所適從,而測試驅動(dòng)開(kāi)發(fā)(Test-Driven Development)就是為了改善傳統的以實(shí)現為目標的軟件開(kāi)發(fā)流程,利用測試來(lái)驅動(dòng)軟件程序的設計和實(shí)現,從測試的角度提出的一種全新的開(kāi)發(fā)方式。測試驅動(dòng)開(kāi)發(fā)可以有效的避免過(guò)度設計帶來(lái)的浪費,同時(shí)也可以讓開(kāi)發(fā)者在開(kāi)發(fā)中擁有更全面的視角,避免過(guò)度實(shí)現帶來(lái)的浪費。因此,測試驅動(dòng)開(kāi)發(fā)成為極限編程中比較流行的一種開(kāi)發(fā)方式,受到很多開(kāi)發(fā)者的青睞。
測試驅動(dòng)開(kāi)發(fā)的整個(gè)過(guò)程跟傳統的軟件開(kāi)發(fā)過(guò)程有很大的區別,它的基本過(guò)程如下:
1) 明確當前要完成的功能?梢杂涗洺梢粋(gè) TODO 列表。
2) 快速完成針對此功能的測試用例編寫(xiě)。
3) 測試代碼編譯不通過(guò)。
4) 編寫(xiě)對應的功能代碼。
5) 測試通過(guò)。
6) 對代碼進(jìn)行重構,并保證測試通過(guò)。
7) 循環(huán)完成所有功能的開(kāi)發(fā)。
為了保證這一過(guò)程能夠快捷方便地進(jìn)行,通常我們會(huì )采用很多開(kāi)發(fā)工具來(lái)支持這一過(guò)程。在應用最為廣泛的開(kāi)發(fā)工具Visual Studio中,因為有.NET Framework的支持,我們可以很輕松方便地進(jìn)行C#和Visual Basic語(yǔ)言的測試,所以使用這兩種語(yǔ)言實(shí)踐測試驅動(dòng)開(kāi)發(fā)也很方便。但是,作為Visual Studio中最重要的開(kāi)發(fā)語(yǔ)言的C++,在以往的Visual Studio的版本中也沒(méi)法方便地進(jìn)行測試。如果要實(shí)踐面向C++語(yǔ)言的測試驅動(dòng)開(kāi)發(fā),我們不得不借助第三方測試工具,比如CPPUnit來(lái)幫助進(jìn)行測試。在整個(gè)過(guò)程中,我們要使用CPPUnit進(jìn)行測試,而開(kāi)發(fā)又是在Visual Studio中進(jìn)行,兩個(gè)工具的銜接協(xié)作,給測試驅動(dòng)開(kāi)發(fā)帶來(lái)了很多不便。使用測試驅動(dòng)開(kāi)發(fā)流程的開(kāi)發(fā)人員熱切地盼望有一個(gè)面向C++的開(kāi)發(fā)工具可以把測試驅動(dòng)開(kāi)發(fā)過(guò)程中最重要的兩個(gè)過(guò)程:“測試”和“開(kāi)發(fā)”結合起來(lái),兩者能夠做到無(wú)縫銜接,讓測試真正地驅動(dòng)開(kāi)發(fā)。
幸運的是,開(kāi)發(fā)人員的這一夢(mèng)想在Visual Studio 2010中成為了現實(shí)。全新的Visual Studio 2010已經(jīng)不僅僅是一個(gè)開(kāi)發(fā)工具,它也集成了大量的測試工具,成為一個(gè)完整的開(kāi)發(fā)平臺。在Visual Studio 2010中,我們可以創(chuàng )建面向C++的測試項目來(lái)完成測試驅動(dòng)開(kāi)發(fā)流程中的測試環(huán)節,從而讓整個(gè)測試驅動(dòng)開(kāi)發(fā)過(guò)程都在Visual Studio中進(jìn)行,讓測試和開(kāi)發(fā)做到了無(wú)縫銜接,而測試也真正地驅動(dòng)了開(kāi)發(fā)。
光說(shuō)不練假把式。為了讓大家更加了解如何在Visual Studio中進(jìn)行面向C++的測試驅動(dòng)開(kāi)發(fā),我們來(lái)看一個(gè)實(shí)際的例子,在例子中體會(huì )這一過(guò)程是多么簡(jiǎn)單方便。例如,我們要編寫(xiě)一個(gè)計算工資的類(lèi)Salary,它可以根據員工的入職年份和現在的年份計算整個(gè)員工應該得到的工資。
按照測試驅動(dòng)開(kāi)發(fā)的過(guò)程,我們首先設計完成這個(gè)Salary類(lèi)需要實(shí)現的功能,為了簡(jiǎn)便,我們讓這個(gè)類(lèi)只需要完成兩個(gè)簡(jiǎn)單的功能:
1) 能夠給定員工的入職年份,并根據現在的年份給出應得的工資
2) 能夠對錯誤的輸入年份返回相應的錯誤代碼
既然是測試驅動(dòng)開(kāi)發(fā),當然是“開(kāi)發(fā)未動(dòng),測試先行”了。按照下面的步驟,首先創(chuàng )建一個(gè)測試項目并編寫(xiě)測試對設計中的功能進(jìn)行測試:
1) 啟動(dòng)Visual Studio 2010并創(chuàng )建一個(gè)新的“Visual Studio空白解決方案”,方案名字叫做SalarySys。接下來(lái)的所有測試和開(kāi)發(fā)都會(huì )在這個(gè)解決方案中進(jìn)行。
2) 向剛剛創(chuàng )建的解決方案中添加一個(gè)Visual C++測試項目SalaryTest。因為我們的測試需要使用C++/CLI進(jìn)行編寫(xiě)以便使用.NET的單元測試框架,所以我們同時(shí)要修改測試項目屬性,讓它使用公共語(yǔ)言運行時(shí)(/clr)支持。
3) 向測試項目SalaryTest中添加一個(gè)單元測試。默認情況下,Visual Studio會(huì )為我們創(chuàng )建一個(gè)UnitTest1.cpp文件,在其中我們就可以編寫(xiě)針對將要實(shí)現的工資計算類(lèi)測試了。
4) 在UnitTest1.cpp文件中找到“#pragma region Additional test attributes”,在這個(gè)區域中,我們編寫(xiě)一個(gè)測試來(lái)對Salary的基本功能進(jìn)行測試。
// 創(chuàng )建測試類(lèi)的智能指針
// 測試功能設計中的“能夠給定員工的入職年份”
std::unique_ptr pClass(new Salary(2003));
// 測試功能設計中的“根據現在的年份給出應得的工資”
// 判斷函數返回結果是否符合預期
Assert::AreEqual(1900, pClass->GetSalary(2006));
這里我們首先創(chuàng )建了一個(gè)Salary類(lèi)的實(shí)例智能指針,其中構造函數的參數2003表示入職年份,然后調用其GetSalary()函數計算工資,其參數2006表示現在的年份。按照設計的計算規則,其結果應該是1300,這里我們使用Assert::AreEqual函數對測試結果進(jìn)行判斷,如果這個(gè)斷言函數通過(guò),則表示這個(gè)Salary類(lèi)的測試通過(guò)。
除了使用Assert::AreEqual斷言函數對結果進(jìn)行判斷之外,Visual C++還提供了多種斷言函數,以滿(mǎn)足對不同類(lèi)型的返回結果進(jìn)行判斷的需要。更人性化的是,我們還可以在斷言函數中添加對測試結果的說(shuō)明,這樣我們更容易以測試的結果來(lái)驅動(dòng)開(kāi)發(fā)。例如:
// 判斷不相等
Assert::AreNotEqual(0, (DWORD_PTR) pClass, "pClass指針不應該為空指針");
// 判斷相等
Assert::AreEqual(0, (DWORD_PTR) pClass, "pClass指針應該為空指針");
// 判斷比較結果是否為true
Assert::IsTrue(pClass == nullptr, "pClass指針應該為空指針");
// 判斷StringValue()返回的字符串是否與期望的結果相等
Assert::AreEqual("期望的結果", gcnew String(pClass->StringValue());
文章來(lái)源于領(lǐng)測軟件測試網(wǎng) http://kjueaiud.com/