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

牽著老婆滿街逛

嚴以律己,寬以待人. 三思而后行.
GMail/GTalk: yanglinbo#google.com;
MSN/Email: tx7do#yahoo.com.cn;
QQ: 3 0 3 3 9 6 9 2 0 .

深入淺出單元測試

作者:老納
一 單元測試概述
  工廠在組裝一臺電視機之前,會對每個元件都進行測試,這,就是單元測試。
  其實我們每天都在做單元測試。你寫了一個函數,除了極簡單的外,總是要執行一下,看看功能是否正常,有時還要想辦法輸出些數據,如彈出信息窗口什么的,這,也是單元測試,老納把這種單元測試稱為臨時單元測試。只進行了臨時單元測試的軟件,針對代碼的測試很不完整,代碼覆蓋率要超過70%都很困難,未覆蓋的代碼可能遺留大量的細小的錯誤,這些錯誤還會互相影響,當BUG暴露出來的時候難于調試,大幅度提高后期測試和維護成本,也降低了開發商的競爭力。可以說,進行充分的單元測試,是提高軟件質量,降低開發成本的必由之路。
  對于程序員來說,如果養成了對自己寫的代碼進行單元測試的習慣,不但可以寫出高質量的代碼,而且還能提高編程水平。
  多數講述單元測試的文章都是以Java為例,本文以C++為例,后半部分所介紹的單元測試工具也只介紹C++單元測試工具。
  要進行充分的單元測試,應專門編寫測試代碼,并與產品代碼隔離。老納認為,比較簡單的辦法是為產品工程建立對應的測試工程,為每個類建立對應的測試類,為每個函數(很簡單的除外)建立測試函數。首先就幾個概念談談老納的看法。
  一般認為,在結構化程序時代,單元測試所說的單元是指函數,在當今的面向對象時代,單元測試的所說的單元是指類。老納認為,以類作為測試單位,復雜度高,可操作性較差,因此仍然應以函數作為單元測試的測試單位,但可以用一個測試類來組織某個類的所有測試函數。單元測試不應過分強調面向對象,因為局部代碼依然是結構化的。單元測試的工作量較大,簡單實用高效才是硬道理。
  有一種看法是,只測試類的接口(公有函數),不測試其他函數,從面向對象角度來看,似乎有些道理。老納認為,測試的目的是找錯并最終排錯,因此,只要是包含錯誤的可能性較大的函數都要測試,跟函數是否私有沒有關系。對于C++來說,可以用一種簡單的方法區隔需測試的函數:簡單的函數如數據讀寫函數的實現在頭文件中編寫(inline函數),所有在源文件編寫實現的函數都要進行測試(構造函數和析構函數除外)。
  什么時候測試?XP開發理論講究TDD,即測試驅動開發,先編寫測試代碼,再進行開發。老納認為,不必過分強調先什么后什么,重要的是高效和感覺舒適。從老納的經驗來看,先編寫產品函數的框架,然后編寫測試函數,針對產品函數的功能編寫測試用例,然后編寫產品函數的代碼,每寫一個功能點都運行測試,隨時補充測試用例。所謂先編寫產品函數的框架,是指先編寫函數空的實現,有返回值的隨便返回一個值,編譯通后再編寫測試代碼,這時,函數名、參數表、返回類型都應該確定下來了,所編寫的測試代碼以后需修改的可能性比較小。
  由誰測試?單元測試與其他測試不同,單元測試可看作是編碼工作的一部分,應該由程序員完成,也就是說,經過了單元測試的代碼才是已完成的代碼,提交產品代碼時也要同時提交測試代碼。測試部門可以作一定程度的審核。
  關于樁代碼,老納認為,單元測試應避免編寫樁代碼。樁代碼就是用來代替某些代碼的代碼,例如,產品函數或測試函數調用了一個未編寫的函數,可以編寫樁函數來代替該被調用的函數,樁代碼也用于實現測試隔離。采用由底向上的開發方式進行開發,先開發的代碼先測試,可以避免編寫樁代碼,這樣做的好處有:減少了工作量;測試上層函數時,也是對下層函數的間接測試;當下層函數修改時,通過回歸測試可以確認修改是否導致上層函數產生錯誤。

二 測試代碼編寫
  下面該說說如果編寫測試代碼了,以一個例子來說明,開發環境是VC6.0。
產品類:
class CMyClass
{
public:
int Add(int i, int j);
CMyClass();
virtual ~CMyClass();
private:
int mAge; //年齡
CString mPhase; //年齡階段,如"少年","青年"
};
建立對應的測試類CMyClassTester,為了節約編幅,只列出源文件的代碼:
void CMyClassTester::CaseBegin()
{
//pObj是CMyClassTester類的成員變量,是被測試類的對象的指針,
//為求簡單,所有的測試類都可以用pObj命名被測試對象的指針。
pObj = new CMyClass();
}
void CMyClassTester::CaseEnd()
{
delete pObj;
}
測試類的函數CaseBegin()和CaseEnd()建立和銷毀被測試對象,每個測試用例的開頭都要調用CaseBegin(),結尾都要調用CaseEnd()。
接下來,我們建立示例的產品函數:
int CMyClass::Add(int i, int j)
{
return i+j;
}
和對應的測試函數:
void CMyClassTester::Add_int_int()
{
}
把參數表作為函數名的一部分,這樣當出現重載的被測試函數時,測試函數不會產生命名沖突。下面添加測試用例:
void CMyClassTester::Add_int_int()
{
//第一個測試用例
CaseBegin();{ //1
int i = 0; //2
int j = 0; //3
int ret = pObj->Add(i, j); //4
ASSERT(ret == 0); //5
}CaseEnd(); //6
}
第1和第6行建立和銷毀被測試對象,所加的{}是為了讓每個測試用例的代碼有一個獨立的域,以便多個測試用例使用相同的變量名。
第2和第3行是定義輸入數據,第4行是調用被測試函數,這些容易理解,不作進一步解釋。第5行是預期輸出,它的特點是當實際輸出與預期輸出不同時自動報錯,ASSERT是VC的斷言宏,也可以使用其他類似功能的宏,使用測試工具進行單元測試時,可以使用該工具定義的斷言宏。
  示例中的格式顯得很不簡潔,2、3、4、5行可以合寫為一行:ASSERT(pObj->Add(0, 0) == 0);但這種不簡潔的格式卻是老納極力推薦的,因為它一目了然,易于建立多個測試用例,并且具有很好的適應性,同時,也是極佳的代碼文檔,總之,老納建議:輸入數據和預期輸出要自成一塊。
  建立了第一個測試用例后,應編譯并運行測試,以排除語法錯誤,然后,使用拷貝已有的測試用例并進行修改的辦法建立其他測試用例。由于各個測試用例之間的差別往往很小,通常只需修改一兩個數據,拷貝修改是最快的建立多個測試用例的辦法。

三 測試用例
  下面說說測試用例、輸入數據及預期輸出。輸入數據是測試用例的核心,老納對輸入數據的定義是:被測試函數所讀取的外部數據及這些數據的初始值。外部數據是對于被測試函數來說的,實際上就是除了局部變量以外的其他數據,老納把這些數據分為幾類:參數、成員變量、全局變量、IO媒體。IO媒體是指文件、數據庫或其他儲存或傳輸數據的媒體,例如,被測試函數要從文件讀取數據,那么,文件中的原始數據也屬于輸入數據。一個函數無論多復雜,都無非是對這幾類數據的讀取、計算和寫入。預期輸出是指:返回值及被測試函數所寫入的外部數據的結果值。返回值就不用說了,被測試函數進行了寫操作的參數(輸出參數)、成員變量、全局變量、IO媒體,它們的預期的結果值都是預期輸出。一個測試用例,就是設定輸入數據,運行被測試函數,然后判斷實際輸出是否符合預期。下面舉一個與成員變量有關的例子:
產品函數:
void CMyClass::Grow(int years)
{
mAge += years;
if(mAge < 10)
mPhase = "兒童";
else if(mAge <20)
mPhase = "少年";
else if(mAge <45)
mPhase = "青年";
else if(mAge <60)
mPhase = "中年";
else
mPhase = "老年";
}
測試函數中的一個測試用例:
CaseBegin();{
int years = 1;
pObj->mAge = 8;
pObj->Grow(years);
ASSERT( pObj->mAge == 9 );
ASSERT( pObj->mPhase == "兒童" );
}CaseEnd();
在輸入數據中對被測試類的成員變量mAge進行賦值,在預期輸出中斷言成員變量的值。現在可以看到老納所推薦的格式的好處了吧,這種格式可以適應很復雜的測試。在輸入數據部分還可以調用其他成員函數,例如:執行被測試函數前可能需要讀取文件中的數據保存到成員變量,或需要連接數據庫,老納把這些操作稱為初始化操作。例如,上例中 ASSERT( ...)之前可以加pObj->OpenFile();。為了訪問私有的成員變量或成員函數,可以將測試類定義為產品類的友元類。例如,定義一個宏:
#define UNIT_TEST(cls) friend class cls##Tester;
然后在產品類聲明中加一行代碼:UNIT_TEST(ClassName)。
  下面談談測試用例設計。前面已經說了,測試用例的核心是輸入數據。預期輸出是依據輸入數據和程序功能來確定的,也就是說,對于某一程序,輸入數據確定了,預期輸出也就可以確定了,至于生成/銷毀被測試對象和運行測試的語句,是所有測試用例都大同小異的,因此,我們討論測試用例時,只討論輸入數據。
  前面說過,輸入數據包括四類:參數、成員變量、全局變量、IO媒體,這四類數據中,只要所測試的程序需要執行讀操作的,就要設定其初始值,其中,前兩類比較常用,后兩類較少用。顯然,把輸入數據的所有可能取值都進行測試,是不可能也是無意義的,我們應該用一定的規則選擇有代表性的數據作為輸入數據,主要有三種:正常輸入,邊界輸入,非法輸入,每種輸入還可以分類,也就是平常說的等價類法,每類取一個數據作為輸入數據,如果測試通過,可以肯定同類的其他輸入也是可以通過的。下面舉例說明:
  正常輸入
  例如字符串的Trim函數,功能是將字符串前后的空格去除,那么正常的輸入可以有四類:前面有空格;后面有空格;前后均有空格;前后均無空格。
  邊界輸入
  上例中空字符串可以看作是邊界輸入。
  再如一個表示年齡的參數,它的有效范圍是0-100,那么邊界輸入有兩個:0和100。
  非法輸入
  非法輸入是正常取值范圍以外的數據,或使代碼不能完成正常功能的輸入,如上例中表示年齡的參數,小于0或大于100都是非法輸入,再如一個進行文件操作的函數,非法輸入有這么幾類:文件不存在;目錄不存在;文件正在被其他程序打開;權限錯誤。
  如果函數使用了外部數據,則正常輸入是肯定會有的,而邊界輸入和非法輸入不是所有函數都有。一般情況下,即使沒有設計文檔,考慮以上三種輸入也可以找出函數的基本功能點。實際上,單元測試與代碼編寫是“一體兩面”的關系,編碼時對上述三種輸入都是必須考慮的,否則代碼的鍵壯性就會成問題。

四 白盒覆蓋
  上面所說的測試數據都是針對程序的功能來設計的,就是所謂的黑盒測試,另外,單元測試還需要從另一個角度來設計測試數據,即針對程序的邏輯結構來設計測試用例,就是所謂的白盒測試。在老納看來,如果黑盒測試是足夠充分的,那么白盒測試就沒有必要,可惜“足夠充分”只是一種理想狀態,例如:真的是所有功能點都測試了嗎?程序的功能點是人為的定義,常常是不全面的;各個輸入數據之間,有些組合可能會產生問題,怎樣保證這些組合都經過了測試?難于衡量測試的完整性是黑盒測試的主要缺陷,而白盒測試恰恰具有易于衡量測試完整性的優點,兩者之間具有極好的互補性,例如:完成功能測試后統計語句覆蓋率,如果語句覆蓋未完成,很可能是未覆蓋的語句所對應的功能點未測試。
  白盒測試針對程序的邏輯結構設計測試用例,用邏輯覆蓋率來衡量測試的完整性。邏輯單位主要有:語句、分支、條件、條件值、條件值組合,路徑。語句覆蓋就是覆蓋所有的語句,其他類推。另外還有一種判定條件覆蓋,其實是分支覆蓋與條件覆蓋的組合,在此不作討論。跟條件有關的覆蓋就有三種,解釋一下:條件覆蓋是指覆蓋所有的條件表達式,即所有的條件表達式都計算了,不考慮計算結果;條件值覆蓋是指覆蓋條件的所有可能取值,即每個條件的取真值和取假值都要計算一次;條件值組合覆蓋是指覆蓋所有條件取值的所有可能組合。老納做過一些粗淺的研究,發現與條件直接有關的錯誤主要是邏輯操作符錯誤,例如:||寫成&&,漏了寫!什么的,采用分支覆蓋與條件覆蓋的組合,基本上可以發現這些錯誤,另一方面,條件值覆蓋與條件值組合覆蓋往往需要大量的測試用例,因此,在老納看來,條件值覆蓋和條件值組合覆蓋的效費比偏低。老納認為效費比較高且完整性也足夠的測試要求是這樣的:完成功能測試,完成語句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋。做過單元測試的朋友恐怕會對老納提出的測試要求給予一個字的評價:暈!或者兩個字的評價:狂暈!因為這似乎是不可能的要求,要達到這種測試完整性,其測試成本是不可想象的,不過,出家人不打逛語,老納之所以提出這種測試要求,是因為利用一些工具,可以在較低的成本下達到這種測試要求,后面將會作進一步介紹。
  關于白盒測試用例的設計,程序測試領域的書籍一般都有講述,普通方法是畫出程序的邏輯結構圖如程序流程圖或控制流圖,根據邏輯結構圖設計測試用例,這些是純粹的白盒測試,不是老納想推薦的方式。老納所推薦的方法是:先完成黑盒測試,然后統計白盒覆蓋率,針對未覆蓋的邏輯單位設計測試用例覆蓋它,例如,先檢查是否有語句未覆蓋,有的話設計測試用例覆蓋它,然后用同樣方法完成條件覆蓋、分支覆蓋和路徑覆蓋,這樣的話,既檢驗了黑盒測試的完整性,又避免了重復的工作,達到非常高的測試完整性。不過,這些工作可不是手工能完成的,必須借助于工具,后面會介紹可以完成這些工作的測試工具。

五 單元測試工具
  現在開始介紹單元測試工具,老納只介紹三種,都是用于C++語言的。
  首先是CppUnit,這是C++單元測試工具的鼻祖,免費的開源的單元測試框架。由于已有一眾高人寫了不少關于CppUnit的很好的文章,老納就不現丑了,想了解CppUnit的朋友,建議讀一下Cpluser 所作的《CppUnit測試框架入門》,網址是:http://blog.csdn.net/cpluser/archive/2004/09/21/111522.aspx。該文也提供了CppUnit的下載地址。
  然后介紹C++Test,這是Parasoft公司的產品。[C++Test是一個功能強大的自動化C/C++單元級測試工具,可以自動測試任何C/C++函數、類,自動生成測試用例、測試驅動函數或樁函數,在自動化的環境下極其容易快速的將單元級的測試覆蓋率達到100%]。[]內的文字引自http://www.superst.com.cn/softwares_testing_c_cpptest.htm,這是華唐公司的網頁。老納想寫些介紹C++Test的文字,但發現無法超越華唐公司的網頁上的介紹,所以也就省點事了,想了解C++Test的朋友,建議訪問該公司的網站。華唐公司代理C++Test,想要購買或索取報價、試用版都可以找他們。老納幫華唐公司做廣告,不知道會不會得點什么好處?
  最后介紹Visual Unit,簡稱VU,這是國產的單元測試工具,據說申請了多項專利,擁有一批創新的技術,不過老納只關心是不是有用和好用。[自動生成測試代碼 快速建立功能測試用例 程序行為一目了然 極高的測試完整性 高效完成白盒覆蓋 快速排錯 高效調試 詳盡的測試報告]。[]內的文字是VU開發商的網頁上摘錄的,網址是:http://www.unitware.cn。前面所述測試要求:完成功能測試,完成語句覆蓋、條件覆蓋、分支覆蓋、路徑覆蓋,用VU可以輕松實現,還有一點值得一提:使用VU還能提高編碼的效率,總體來說,在完成單元測試的同時,編碼調試的時間可能還會縮短。算了,不想再講了,老納顯擺理論、介紹經驗還是有興趣的,因為可以滿足老納好為人師的虛榮心,但介紹工具就覺得索然無味了,畢竟工具好不好用,合不合用,要試過才知道,還是自己去開發商的網站看吧,可以下載演示版,還有演示課件,老納念經去也,阿彌陀佛。

posted on 2006-07-05 22:22 楊粼波 閱讀(200) 評論(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>
            欧美日韩精品久久久| 亚洲欧美国产va在线影院| 久久久精品性| 欧美一级播放| 国内成人精品一区| 另类春色校园亚洲| 美女999久久久精品视频| 亚洲人精品午夜| 99re6热只有精品免费观看| 欧美午夜在线视频| 久久av红桃一区二区小说| 久久精品成人一区二区三区蜜臀| 亚洲国产精品成人精品| 91久久一区二区| 欧美日韩mv| 久久九九国产精品| 欧美第十八页| 久久精品观看| 欧美成人资源| 久久精品一区二区三区不卡牛牛 | 一本色道久久综合亚洲精品按摩 | 久久综合久久美利坚合众国| 老牛影视一区二区三区| 在线视频日本亚洲性| 午夜精品福利一区二区蜜股av| 亚洲高清123| 亚洲视频在线免费观看| 亚洲国产美国国产综合一区二区| 一区二区三区久久网| 亚洲电影免费观看高清完整版在线| 99精品国产在热久久下载| 韩国一区电影| 一本色道久久综合亚洲91| 亚洲国产精品成人| 性欧美video另类hd性玩具| 99视频超级精品| 久久精品中文字幕一区| 亚洲女性喷水在线观看一区| 美国十次了思思久久精品导航| 久久精品国产清自在天天线| 欧美日韩美女在线观看| 欧美成人69av| 极品尤物av久久免费看| a4yy欧美一区二区三区| 亚洲精品之草原avav久久| 欧美中文日韩| 久久精品久久综合| 国产精品嫩草影院一区二区| 亚洲精品亚洲人成人网| 亚洲欧洲精品一区| 久久综合给合久久狠狠狠97色69| 久久国产乱子精品免费女| 国产精品theporn| 亚洲日本欧美日韩高观看| 欧美影院一区| 午夜精品久久一牛影视| 欧美日韩在线综合| 日韩视频永久免费| 亚洲精品资源| 欧美久久综合| 99国产精品一区| 在线午夜精品自拍| 欧美日韩综合不卡| 一区二区三区蜜桃网| 亚洲一区二区三| 国产精品ⅴa在线观看h| 中文国产一区| 久久精品电影| 尤物九九久久国产精品的特点 | 欧美猛交免费看| 日韩视频在线观看国产| 亚洲一区精品电影| 国产精品一区在线播放| 欧美一区=区| 你懂的一区二区| 99视频超级精品| 国产精品黄色在线观看| 午夜精品一区二区三区在线| 久久男女视频| 亚洲精品一区久久久久久| 欧美日韩国产综合新一区| 中文有码久久| 老牛嫩草一区二区三区日本| 亚洲欧洲一区二区三区在线观看| 欧美日韩国产大片| 亚洲欧美精品伊人久久| 久久综合色婷婷| aaa亚洲精品一二三区| 国产精品―色哟哟| 久久视频在线免费观看| 亚洲日本免费| 久久国产手机看片| 黄色成人av网站| 欧美精品久久天天躁| 亚洲伊人观看| 亚洲国产成人午夜在线一区| 亚洲一区二区欧美日韩| 影音先锋久久久| 欧美午夜精品久久久久久孕妇| 亚洲永久网站| 欧美激情视频在线免费观看 欧美视频免费一 | 国产日韩欧美中文在线播放| 欧美成人精品影院| 亚洲欧美bt| 亚洲人成7777| 老**午夜毛片一区二区三区| 亚洲视频香蕉人妖| 亚洲第一在线| 国产欧美精品日韩| 欧美日韩国产综合一区二区| 久久精品亚洲一区二区| 一本久久综合亚洲鲁鲁五月天| 蜜桃av噜噜一区| 午夜精品久久久久久99热软件| 亚洲日本一区二区| 国产欧美在线观看| 欧美性开放视频| 欧美理论在线播放| 久久久综合网站| 午夜精品免费在线| 亚洲视频在线免费观看| 最新中文字幕一区二区三区| 亚洲国产一区二区三区青草影视| 欧美体内she精视频| 欧美四级剧情无删版影片| 国产视频丨精品|在线观看| 亚洲视频欧美在线| 亚洲高清激情| 国产精品久久久久久久久免费桃花 | 亚洲色图在线视频| 亚洲国产精品久久久久秋霞不卡| 欧美精品电影在线| 国语精品一区| 国产视频一区在线观看| 国产精品毛片a∨一区二区三区| 欧美激情一区二区三区| 欧美阿v一级看视频| 麻豆国产精品va在线观看不卡 | 母乳一区在线观看| 久久久久天天天天| 久久成人综合视频| 久久国产精品一区二区| 久久黄色网页| 久久人91精品久久久久久不卡| 久久精品中文字幕一区| 久久久久高清| 美女免费视频一区| 美女诱惑黄网站一区| 欧美1区视频| 亚洲国产女人aaa毛片在线| 欧美激情一区二区三区在线视频| 亚洲福利精品| 99在线精品免费视频九九视| 99国产成+人+综合+亚洲欧美| 亚洲精品一区在线观看香蕉| 一区二区欧美在线观看| 亚洲一区二区三区久久| 亚洲欧美综合v| 久久偷看各类wc女厕嘘嘘偷窃| 老司机午夜精品视频| 欧美理论片在线观看| 国产精品另类一区| 国内精品视频一区| 亚洲剧情一区二区| 亚洲一二三区视频在线观看| 欧美一区二区三区四区在线| 久久夜色精品亚洲噜噜国产mv| 欧美激情a∨在线视频播放| 日韩网站在线观看| 性欧美大战久久久久久久免费观看| 久久女同精品一区二区| 欧美日韩和欧美的一区二区| 国产日本欧美一区二区| 亚洲国产精品福利| 亚洲欧美激情一区| 欧美v国产在线一区二区三区| 99国产精品久久久久老师| 久久爱www久久做| 欧美激情一区二区三区蜜桃视频| 国产精品久久久一区二区三区| 激情欧美一区二区三区| 99国产精品私拍| 久久青草福利网站| 一区二区三区欧美成人| 久久久久国产精品一区三寸| 欧美日韩综合在线免费观看| 在线观看成人小视频| 亚洲欧洲99久久| 亚洲激情网址| 久久精品一本久久99精品| 欧美天堂在线观看| 亚洲国产日韩在线| 欧美与黑人午夜性猛交久久久| 国产专区欧美精品| 一区二区在线视频观看| 亚洲一区二区3| 亚洲国产精品毛片| 久久久久久久久一区二区| 国产精品免费aⅴ片在线观看| 亚洲美女91|