第4代白盒測试方法介绍--理论篇
關鍵詞: 白盒測試 第4代 測試方法 4GWM 在線測試 持續測試 灰盒 腳本驅動 腳本樁
摘? 要: 本文是第4代白盒測試方法的理論介紹,描寫敘述3個關鍵領域內9項關鍵特征的概念與固有特征。同一時候介紹白盒測試發展歷程,對照說明第4代白盒測試方法與以往測試方法的異同及優化要素。
縮略語:
4GWM:The 4th Generation White-box-testing Methodology,第4代白盒測試方法
XP:Extreme Programming,極限編程
TDD:Test Driven Development,測試驅動開發
IID:Incremental and Iterative Development,漸增迭代開發
CSE:Common Script Engine,通用腳本引擎(一種近似于python的腳本語言)
PCO:Points of Control and Observation,觀察控制點
TDF:Test Design First,測試設計先行
MCDC:Modified Condition/Decision Coverage
?
1背景
1.1白盒測試的范圍
白盒測試是軟件測試體系中一個分支,測試關注對象是一行行可見代碼,假設代碼不可見就不是白盒,是黑盒測試了。白盒測試也通常被覺得是單元測試與集成測試的統稱,但這個概念是相對的,與當前項目遵循的研發流程有關,某些流程把白盒測試劃分為單元測試與集成測試,而另一些流程,把白盒測試劃分為模塊單元測試、模塊系統測試、多模塊集成測試,另一些流程把單元測試與集成測試混為一體,統稱為持續集成測試。
隨著測試技術的發展,白盒測試的概念也在發生變化,比方,本文提倡一種介于白盒與黑盒之間的灰盒操作模式,針對被測對象相同是可見源代碼,這時,白盒測試不僅僅是白盒了。雖然假設此,我們仍遵循大家習慣的思維方式——把本文倡導的測試方法仍冠名為:第4代白盒測試方法(4GWM,The 4th Generation White-box-testing Methodology)。
本文討論白盒測試方法,范圍限定在功能測試之前,針對源代碼行的全部測試,即,被測對象是看得到的功能源代碼,每一個測試者必須先獲得源代碼才干實施測試。
1.2第1代與第2代白盒測試
說到第4代白盒測試方法,就不能不回想前幾代方法。在測試發展初期,測試工具非常不成熟,人們通常以單步調試取代測試,或採用assert斷言、print語句等簡單方式的組織測試體系,即我們所謂的第1代白盒測試,這一時期的測試是半手工的,沒實現自己主動化,測試效果也嚴重依賴測試者(或者調試者)的個人能力,缺少統一規范的評判標準。
當然,調試算不算測試在業界尚存爭議,單論調試的目的(為了定位問題)與操作方式(過程不可反復),不應把調試看作測試,但調試確能發現軟件BUG,顯然這也是一種測試手段。本文暫不評判調試用作測試手段是否合理,但有必要先確定調試是測試的某種形式,把它看作特定歷史階段或特定場景下的產物。特定歷史階段大家比較easy理解,調試伴隨編程語言是天生的,測試工具卻是后天形成,開發者總喜歡認調試器當親媽,測試工具則是愛管無論的后媽。特定場景是什么?比方,某種生僻的RTOS平臺根本找不到相應測試工具,怎么辦?拿調試做測試是無奈之中的必定。這里,我們不否認調試也是一種測試,在此基礎上再優化其操作過程,使調試能更好的服務于測試(下文介紹“灰盒調測”還有進一步論述)。
第1代白盒測試方法存在嚴重缺陷,主要有:測試過程難以重用,成功經驗無法拷貝,測試結果也難以評估并用于改進,這些對于團隊運作是很致命的。
到第2代白盒測試,上述主要缺陷得到克服,將測試操作改用一種形式化語言(通常稱為測試腳本)來表述,腳本能夠組合成用例,用例可組合成測試集,用例與測試集再統一到測試project中管理,把測試腳本保存到文件,重用問題攻克了。另外,代碼覆蓋率功能使測試結果能夠評估,能直觀的看到哪些代碼或分支未被覆蓋,然后有針對性的添加測試設計。眼下市面上有大量商用工具,如RTRT、CodeTest、Visual Tester、C++ Tester等都屬于這第2代白盒測試工具。
1.3第3代白盒測試方法
按理說,第2代白盒測試工具已經非常完好了,那第3代又是什么?
軟件測試是一門復雜科學,支持自己主動測試與覆蓋率評估后不見得就能成功實施白盒測試,尤其重要的是,第2代白盒測試攻克了反復測試問題,但沒解決持續測試問題。簡單來說,反復測試使測試操作能以規范格式記錄,當被測對象沒變化(或變化非常少)時,測試用例是可重用的,但假設源代碼大幅調整(甚至重構),或者按迭代模式不停追加新功能時,怎樣維持用例同步增長,并與源代碼一起同步更新,已經不是簡單的增強用例復用能力就能解決的。由于代碼更新與用例更新交織進行,測試用例與被測源代碼一樣對等的成為日常工作對象,必定促使原有工作模式與測試方法產生變革,概括而言,白盒測試過程要從一次測試模式過渡到持續測試模式。
第3代白盒測試工具以xUnit為代表,包含JUnit、DUnit、CppUnit等,當然,我們列舉xUnit工具,并不說這些第3代工具就比第2代工具要好。其實,眼下xUnit工具在功能上普遍趕不上第2代商用工具,很多xUnit工具甚至連主要的覆蓋率都支持不了,況且,xUnit使用被測代碼的編程語言寫用例,普遍效率低下。這里,我們區別第2代方法與第3代方法,主要是測試理念上區別,而不以工具區別為基準,由于工具配套跟進還與諸多現實因素相關,是還有一層面話題。
1.4第4代白盒測試方法的產生背景
xUnit是XP實踐的重要支撐工具,XP作為一種軟件開發方法論,整體盡管敏捷,但非常脆弱,它對程序猿非常友好,但對組織不是。以xUnit為代表的XP測試實踐相同表現出這一特質,據已有案例分析,XP持續集成在java項目中成功的非常多,C++有一些, C語言項目就非常少了,為什么編程語言對持續集成的影響如此深遠?
第4代白盒測試嘗試解決軟件測試的深層次矛盾:測試的投入產出比問題。大家知道,研發資源總是有限的,你能夠把測試人員與開發者的比例配到1:1,也能夠配到2:1,甚至5:1,但你做不到10:1、100:1,假設你有錢,也有人,全然能夠按100:1或更高比例配置,這時全部測試瓶頸都沒了,你能夠讓測試人員邊喝咖啡邊干活,由于每新寫1行代碼總有人編出100行腳本測試它,還怕產品不穩定嗎?只是,瘋子才會這么做,比爾蓋茲有的是錢,一年捐款十多億美金,但不見得微軟旗下產品就常常讓測試人員比開發者多出一倍。我的意思是,測試資源必定是受限的,這個前提下我們才討論第1代、第2代白盒測試向第3代、第4代演化的必要性。基于相同原理的xUnit工具,針對不同開發語言效果截然不同,這說明什么?說明這樣的實踐的瓶頸仍在投入產出比上,也就是上面所說的1:1效果,還是2:1,抑或是5:1效果。
高效平臺下的高效工具能夠大幅提高測試效率,測試投入與開發投入之比小于1:1就能保證測試質量,項目就成功了,而低效平臺下的低效工具,必定要投入很多其它測試資源(例如5:1)才干保證效果,拐點就在這兒,哪個公司禁得起5:1的測試投入?!從這個意上說,推出第4代白盒測試方法意義重大,我們要嘗試解決決定項目成敗的拐點問題。
事先申明一下,下文涉及持續集成與測試先行(或稱測試驅動開發,TDD)實踐,盡管這兩者都是XP的重要組成部分,但我們無意宣揚XP,其實,真正能適應XP的項目范圍并不寬,跳過需求與預設計直接啟動項目的做法,足以讓客戶敬而生畏,把文檔丟給獅子,那是無政府主義散兵游勇行徑。只是,XP確有很多閃閃發光的實踐,持續集成僅僅要運用恰當還是不錯的模式,測試先行的理念也不賴,僅僅要只是度實施就好。
2什么是第4代白盒測試方法
第4代白盒測試方法(4GWM)針對前幾代測試方法不足提出,很多理念仍繼承第2代與第3代測試方法。下表簡要的列出第1代到第4代白盒方法的主要區別:
| ? | 是否評估測試效果
| 是否自己主動測試
| 是否持續測試
| 是否調測一體
|
| 第1代白盒測試方法 | 否 | 否 | 否 | 否 |
| 第2代白盒測試方法 | 是 | 是 | 否 | 否 |
| 第3代白盒測試方法 | 是 | 是 | 是 | 否 |
| 第4代白盒測試方法 | 是 | 是 | 是 | 是 |
上表中,“是否評估測試效果”指是否有覆蓋率或其他評估測試效果的指標,“是否自己主動測試”指是否形式化描寫敘述測試操作并將它用于再次測試,“是否持續測試”指是否以按持續集成的模式開展測試,“是否調測一體”指是否將測試設計高效的融入產品編碼與調試的日常實踐之中。
第2代白盒測試與第3代的分水嶺在于“是否持續集成”,也許您會說,我的項目也是常常出版本號,重復追加測試用例的呀,請注意,這是兩個概念,Joel測試——改進代碼的12個步驟中有一條:“編寫新代碼之前先修復故障嗎?”,先修復故障是質量優先的項目,否則進度優先,這是兩種全然不同的行事風格,前者時時測試,始終每寫一兩個函數就補全相關測試用例,測試實踐是融入開發全過程的,而后者依時間表行事,測試僅是特定階段里的任務。
對了,測試方法怎么跟軟件開發方法扯上了?由于測試不是孤立的,測試是否有效強烈依賴于軟件project方法,就像早期的開發語言,僅僅有assert語句與測試相關,發展到現有的C#,單元測試框架也是該語言的固有組件了。測試腳本也是一種產品代碼,測試方法實際與軟件開發方法密不可分的,這在第3代與第4代白盒測試中體現得非常充分。
第4代白盒測試方法相對第3代方法,添加了將測試過程(包含測試設計、運行與改進)高效的融入開發全過程,這里,“高效的”是關鍵詞,那怎樣才算高效呢?我們先簡單了解4GWM在3個關鍵領域的9項關鍵特征,例如以下:
A.????? 第一關鍵域:在線測試
1、? 在線測試驅動
2、? 在線腳本樁
3、? 在線測試用例設計、執行,及評估改進
B.????? 第二關鍵域:灰盒調測
4、? 基于調用接口
5、? 調試即測試
6、? 集編碼、調試、測試于一體
C.????? 第三關鍵域:持續測試
7、? 測試設計先行
8、? 持續保障信心
9、? 重構測試設計
3為什么持續集成
為什么要持續集成?這個問題太重要了,我們專門拎出來講,請大家先不急于跳過本章去看4GWM的9個關鍵特征怎么定義的。
3.1 JOEL測試
Joel是個怪人,當然他不認識我,我拜讀他的Blog才知道他的。這家伙總有很多稀奇古怪的思想在小腦瓜里蹦達,他是“常常放貓出來閑逛”的人。科學研究表明,人的大腦僅僅占體重2%,卻消耗20%的能量,當大腦思考問題時,釋放出的能量等同于夜間放一僅僅貓出來活動。他的“Joel說軟件”專欄(www.joelonsoftware.com)非常火,有一些不乏真知灼見。比方,Joel測試——改進代碼的12個步驟:
1、? 有版本號控制機制嗎?
2、? 能一步完畢編譯鏈接嗎?
3、? 每天都做編譯嗎?
4、? 使用缺陷跟蹤庫嗎?
5、? 編寫新代碼之前先修復缺陷嗎?
6、? 有最新的進度表嗎?
7、? 有規格說明書嗎?
8、? 程序猿擁有安靜的工作環境嗎?
9、? 你用到了你資金能力內可買到的最好工具嗎?
10、? 有測試人員嗎?
11、? 要求新聘人員在面試時編寫代碼嗎?
12、? 進行走廊可用性測試嗎?
每一個問題能夠回答“是”或者“否”,答“是”則加1分,得12分是完美,11分勉強接受,10分下面問題就大了,大家有興趣看看你所在的組織能打多少分。
有測試人員嗎?干嘛這么問,沒測試人員還叫軟件公司嗎?這個問題并不可笑,還真有不少公司從未配置過專職測試人員。某白熾燈生產商在使用說明中特意聲稱,燈泡不能往嘴里塞,否則會出嚴重醫學事故,說明書中還鄭重其事的介紹燈泡不慎入口后,怎樣求醫,怎樣抹潤滑劑,怎樣左轉90度右轉90度慢慢取出來。有人認為滑稽,誰白癡有事沒事拿燈泡往嘴里送?即使放嘴里了也不用這么麻煩吧?非得試試,結果怎樣?怎么也拿不出來了,僅僅得嘴里叼個燈泡打的上醫院,最后,醫生依照說明書費老勁才將那玩意卸下。所以,不要輕易否定前人經驗,早有人試過了。
看看上面12個步驟,前5步活脫脫在講怎樣實施持續集成,若進一步了解其內容,大家最好還是瀏覽Joel的Blog原文。
3.2 持續集成不是XP專有實踐
持續集成屬于IID(持續迭代開發)方法學,在測試上,就現實而論是以xUnit實踐為代表,持續集成概念被XP刻上深深烙印,但它確非XP專有實踐。
早在20世紀60年代IBM的Federal Systems Division就開始應用IID開發模式了,源于IBM的集成產品開發流程(IPD)相對CMM,有個顯著特征,它支持漸增迭代開發,盡管迭代頻度比不上微軟每日構造,但其理念仍是持續的迭代開發。有意思的是,IPD流程在華為公司本土化后,發展出“版本號火車”理論,有點相似于Scrum實踐了,版本號火車不僅讓產品(一般是大產品)版本號公布更加規范有序(由于火車總是定點出發的),也推動研發以更快頻度推陳出新。
但眼下持續集成仍在有限范圍能成功應用,微軟無疑是個樣板,畢竟純軟件產品easy實施每日構造,還有不少實踐XP的項目,持續集成也運用得非常成功。所以,就總體而言,持續集成是否能成功,已經不是方法論問題,很多其它是IT工具怎樣支撐的問題。
3.3 為什么持續集成
我們看一個實際案例,某通信產品在V1版本號編碼完畢時,進行過規范的單元測試活動,之后V2、V3要不斷添加功能、改動功能,就放棄單元測試了,當V3最后市場交付時統計發現,相對V1版本號,代碼改動量已達到40%。QA從當中兩個模塊隨機抽取100個問題單做缺陷分析,結果發現:第一個模塊有50%的問題是在V1版本號單元測試結束后引入的,而還有一模塊也有30%問題是單元測試后引入的。
也就是說,在第一次完整單元測試之后,代碼改動了40%,也因此產生了40%的問題,因為增量白盒測試難以實施,這些問題都被遺留到后期功能測試中才發現。單元測試沒能持續開展,帶來后果是:發現問題不徹底,付出代價也更高。
上述模式在業界還普遍存在,我們稱為一次測試,與持續測試不同,一次測試的測試設計僅僅做一次,用例仍可反復拿來跑,由于測試腳本與源代碼不同步,用例維護是間歇進行的,或者干脆不維護。注意,一次測試與持續測試的區別不在于用例是否可重用,而在于測試設計的持續性。
很多企業做不到持續測試,其主要原因不是不想做,第一次測試都認真做了,追加代碼或改動代碼當然也要做測試,做不了是由于操作上存在困難。持續測試是須要一開始就規劃,測試工具要配套跟進才干順利實施的,對于老產品,代碼修修補補,不管一次測試還是持續測試都非常難做得好。
引入持續測試,不僅以更低代價發現很多其它問題,更重的是,它體現了一個組織在測試理念上有質的飛躍。一次測試是一種被動測試,開發者受制于組織紀律(或主管、QA等壓力)才去做,而持續測試是主動測試,大家在測試中嘗到甜頭,從原先不自覺狀態,過渡到自發、自覺的時時做測試。這兩種情形無疑有天差地別,前面提到的Joel測試12步驟,實際上是微軟實踐,與持續集成相關的有5條,足見它的重要性,是否引入持續集成,以及實施的效果怎樣,實際反映了一流公司與二流公司的差距。
4第4代白盒測試方法的關鍵特征
白盒測試是一項實踐性非常強的技術,我們講第4代白盒測試方法,離不開相關測試實踐,尤其是測試工具支撐。本文的上篇先從理論上介紹什么是4GWM,下篇則結合詳細測試工具介紹4GWM的典型實踐。
4.1在線測試
4GWM第一個關鍵域是在線測試,包含3個關鍵特征:
2????? 在線測試驅動
2????? 在線腳本樁
2????? 在線測試用例設計、執行,及評估改進
一次白盒測試中(即一個用例中)我們關注被測單元功能是否實現,被測單元作為總體,在特定環境下執行(比方某些全局變量取特定值、某些依賴線程或任務已啟動等),具有特定的輸入輸出,這幾項都屬于“測試驅動”。另外,被測單元若能正確執行,還依賴它調用的子函數是否提供正常功能,這些子函數我們稱為“測試樁”。分層結構例如以下圖:
在三層實體中,被測單元是測試關注對象,要求盡可能真實,我們設法維持其原狀,測試驅動與測試樁能夠模擬(或叫仿真),同意存在一定失真,但要求盡可能高效,否則測試產出的拐點問題解決不了。
4.1.1腳本驅動與腳本樁
先回答一個基礎問題,編寫測試用例應優先採用腳本語言,而不與被測代碼使用同一的語言,為什么?
還是應為軟件測試的深層次問題——投入產出比,假設被測編程語言的抽象度較低、封裝性差,用起來就非常麻煩。比方拿C或C++寫測試用例,得處處小心內存操作,要正常申請釋放、注意不越界,時常關心使用變量是否安全、是否已初始化等。或許有人說,不正確, CppUnit中拿C++測C++,我用得非常爽呀?噢,沒錯,我得先恭喜這位老兄,安于現狀不失為一種好品質。
我們設想一下,編寫一萬行C++代碼,你要寫多行代碼測試它,一千行?兩千行?不正確,是一萬行,按業界普遍規律,測試代碼行至少要與被測代碼行數相當才見效果,測試代碼要不要調試?當然要調,天哪,算出來的了,測試投入至少是開發投入的三、四倍才做得下來(后期還有功能測試、性能測試、兼容性測試等等,還要占用大量精力),這種項目是不是處在是否能成功的拐點上?所以,假設您還在用C、C++等過程語言寫用例,請盡快換到腳本語言,如python、ruby、CSE等,用腳本語言能讓你編寫用例的效率提高3到5倍。
用腳本編寫用例,意味著測試驅動與測試樁仿真也用腳本語言。我們看一下VcTester工具使用的測試腳本,假定被測對象是C代碼的冒泡排序算法:
void BubbleSort(OBJ_DATA_PTR *ObjList, int iMax)
{
? int i,j,exchanged;
? OBJ_DATA *tmp;
?
? for (i = 0; i < iMax; i++) // maximum loop iMax times
? {
????? exchanged = 0;
????? for (j = iMax-1; j >= i; j--)
????? {
????????? if ( ObjCompare(ObjList[j+1],ObjList[j]) < 0 )
????????? {?? // exchange the record
????????????? tmp = ObjList[j+1];
????????????? ObjList[j+1] = ObjList[j];
????????????? ObjList[j] = tmp;
????????????? exchanged = 1;
????????? }
????? }
????? if ( !exchanged ) return;
? }
}
排序函數(BubbleSort)中調用了對象比較函數(ObjCompare),假定當前測試對象是BubbleSort函數,我們編寫測試用比例如以下:
func StubFunc(vc):
? if vc.arg0->Data() < vc.arg1->Data():
??? return -1;
? end else return 1;
end;
vd.ObjCompare.stub(StubFunc);? # 打腳本樁
vd.BubbleSort(vd.gList,6);? ????# 發起測試
assert(vd.gList[0]->Data <= vd.gList[1]->Data); # 檢查測試結果
vd.ObjCompare.stub(nil);??????? # 清除腳本樁
腳本驅動是指將被測系統的全局變量與全局函數映射到腳本系統,然后使用腳本讀寫C語言變量,調用C語言函數。在VcTester中,C語句的全局變量與函數映射到腳本的vd集合下,如上面腳本使用“vd.gList”讀取C變量,使用“vd.BubbleSort()”調用C函數。
腳本樁是指定義一個腳本函數,然后讓這個腳本函數取代某個C函數,打腳本樁是為了讓一段腳本化測試邏輯,在動態運行中,取代被測系統中的樁函數。由于測試中我們常常要讓某些子函數返回特定值,使被測函數的特定路徑能被覆蓋。上面樣例定義了一個腳本樁函數StubFunc,拿這個腳本函數模擬對象比較功能,通過打樁替換C函數ObjCompare。
4.1.2在線測試邏輯更新
4GWM引入腳本驅動與腳本樁,不僅僅是提高測試設計效率,還以此保障在線測試。所謂在線測試,是指被測程序啟動后,用例在線設計、調試、執行,執行結果在線查看的測試方法。由于全部測試操作都在線進行,測試用例不必編譯鏈接,被測程序也不用復位重起,被測環境(被測系統的變量、函數等屬性)在線可查看,所以該測試模式非常高效,另外,各測試步驟所見即所得,人性化的操作過程非常easy被廣大開發者接受。
腳本語言具有在線更新功能,比方定義一個腳本函數,調用一次后,發現某個地方處理不正確,于是重寫這個函數,然后在線的更新這個函數定義。編譯語言做不到這一點,改動代碼后必須又一次編譯鏈接,程序要復位重起,腳本語言省去了這些繁瑣過程。比方,在GUI界面編寫測試用例,定義測試樁函數,然后選擇待運行的腳本區塊,按一個快捷鍵,指定范圍的腳本就運行,相關腳本函數定義馬上被更新,腳本運行后的測試結果也馬上打印輸出。
4.1.3拉通測試小循環
測試用例設計、調試、運行,及評估改進是一個閉環迭代,例如以下圖:
?
?
測試結果評估主要是覆蓋率指標,包含:語句覆蓋、分支覆蓋、組合條件覆蓋等,結果評估也是在線進行的,用例運行后,隨即在線查閱覆蓋率情況,針對未覆蓋部分再添加用例。
當上圖4個步驟都能在線操作后,測試小循環就拉通了,4GWM的第一個關鍵域(在線測試)的目的就在這兒,拉通測試小循環,是大幅度提高測試工作效率的第一環節。接下來通過灰盒調測,拉通開發大循環是提高效率的第二環節。
4.2灰盒調測
4GWM第二個關鍵域是灰盒調測,包含3個關鍵特征:
2????? 基于調用接口
2????? 調試即測試
2????? 集編碼、調試、測試于一體
4.2.1白盒測試的粒度
白盒測試關注被測函數的功能表現,要關注到什么程度,在不同的測試實踐與測試工具中要求各不同。我們能夠簡單的分為3個級別,一是源代碼行級別,二是函數調用級別,三是組件接口級別。
源代碼行級別具有調試特征,能夠關注到函數內局部變量,當測試停留于該級別會顯得過于細碎,由于結構化程序開發總是以函數為單位逐級劃分功能的,函數內的代碼穩定性差,變量定義常常變化,過程處理也常常調整。組件接口級別的測試對象僅關注到組件接口,如Corba接口、控件調用接口、消息隊列接口等,這一級別的白盒測試無疑偏于粗放。
4GWM規定的白盒測試關注粒度是函數調用接口,即,測試設計僅僅關心函數的輸入、輸出,及該函數執行中對全局變量的影響,遵循例如以下原型:
設計測試用例,先通過腳本構造被測函數的輸入參數,改動特定全局變量,使被測函數處于某特定執行環境下,這兩步屬于測試驅動。然后調用被函數,最后推斷測試結果,由于執行被測函數可能影響輸入參數、全局變量與返回值,所以推斷用例是否執行通過,觀察對象也是這三者。在用例設計過程中,我們并不關心函數內局部變量怎樣聲明,也不關心函數內邏輯過程怎樣處理,僅僅關心被測對象的輸入與輸出,這是一種典型的黑盒思維模式。
準確來說,4GWM是一種灰盒測試方法,雖然操作方式是黑盒的,但測試設計是白盒的,由于看得見源代碼,測試設計能夠有針對性的進行,測試過程評估也是白盒的,執行一遍用例后,查看哪些代碼行有沒跑到,再有針對性補充用例。所以,我們從總體來看,4GWM是介于黑盒與白盒之間的灰盒測試。
依據已有實踐判斷,上述灰盒模式關注的測試粒度是恰如其分的,既避開了調試操作的任意性,也使測試用例建立在較穩健的基礎之上,僅僅要函數調用接口沒變,局部變量改了或邏輯過程調整了,就不會影響已實用例。同一時候,黑盒操作方式附帶白盒分析模式,保障了4GWM具有高效、便捷的特性。
4.2.2檢視器
檢視器(Inspector)是4GWM推薦的測試輔助工具,它介于測試器(Tester)與調試器(Debugger)之間,是一種可以提供腳本化控制的粗粒度的調試器。使用檢視器有助于把無規則的調試過程轉化為規范的測試過程。
檢視器有兩種執行模式:斷點調試模式與測試模式。前者在斷點條件滿足時進入單步跟蹤狀態,后者在斷點上附加特定腳本語句(比方改動變量、檢查變量值等),當斷點條件滿足附加語句即自己主動執行,此時斷點僅作為一個觀察控制點(Points of Control and Observation,PCO)存在,不用作交互調試目的。
一次典型的檢視步驟例如以下圖所看到的:
?
首先在被測函數上設置斷點,接著用腳本構造調試環境,包含改動變量、設置腳本樁等,然后發起測試,在斷點觸發后的單步跟蹤狀態,觀察各個變量值是否預期,還能夠改動變量使被測函數中特定分支能夠運行。最后在調試完畢時,能夠將當前調試操作,包含設置斷點、檢查變量值是否預期、改動變量等,自己主動轉化為測試腳本。
上述檢視操作向自己主動腳本轉換還解決測試數據構造問題,尤其在復雜系統中,構造測試數據比較麻煩,比方通信協議的消息包數據,創建消息后要填寫數十,甚至數百個字段的值。 檢視操作能夠在函數調用鏈中插入一段腳本代碼,比方被測代碼先調用一個初始化協議消息的函數,得到正確消息包后傳遞給被測函數,我們通過插入腳本,在被測函數執行之前改動傳入消息包的特定字段,從而實現特定路徑的覆蓋測試。採用該方法設計用例是很便宜的,直接重用被測系統的局部功能,免去了繁重的測試驅動構造工作。
檢視過程相似于調試,主要區別例如以下:
1.???????? 檢視器斷點僅僅在函數入口設置,調試器能夠在隨意語句設斷點。
2.???????? 檢視既能夠在IDE界面手工操作,也能夠通過寫腳本控制,調試器一般僅僅支持手工操作。
3.???????? 檢視器在斷點狀態下能夠執行隨意合法的測試腳本,調試器無此功能。
因為檢視器與編程語言自帶的調試器實現原理不同,普通情況下兩者能夠同一時候使用,可同一時候設置檢視斷點與調試斷點。
4.2.3調試就是測試
調試為了定位問題,測試是為了發現問題,兩者雖不能互相替換,但當測試手段趨于豐富,測試工具也能越來多的承擔調試職責。讓測試工具承擔部分調試功能,可在例如以下方面獲益:
1.?????? 調試與測試共享執行環境
被測代碼片斷是在特定環境下執行的,不管調試還是測試,都得先構造執行環境,比方準備特定的數據、改動狀態變量、啟動特定線程或任務。借助測試工具在線構造測試驅動與測試樁,調試環境能便利的搭建起來,并且,構造執行環境的腳本能直接在相關測試用例中重用。
2.?????? 將不可反復的調試轉化為可反復的測試
調試過程具有任意性與不可反復性,在哪兒設斷點、怎樣看變量、怎樣單步跟蹤都因人而異。調試的操作過程難被重用,不像測試用例,以形式化腳本記錄操作過程,想怎么反復就怎么反復,上節介紹的檢視器就是一種可反復的調試器。
操作自己主動反復是提高工作效率的基本途徑,不必強求全過程反復,片斷可反復就能大幅提高效率了。
3.?????? 測試設計能夠非常好的重用被測系統中局部功能
如上一節舉例,直接調用被測系統的消息構造函數,能避開繁重的協議消息仿真工作。
4.?????? 解決腳本調試與源代碼調試的交叉影響問題
實踐證明,白盒測試的大部分時間消耗在腳本編寫與調試中,調試好的用例,運行差點兒不要時間(即使要時間,挪到晚上讓它自己自己主動跑好了)。測試腳本調試與源代碼調試是交叉進行的,單元測試中的源代碼與測試腳本都不穩定,通常我們讓腳本發起測試,須同一時候跟蹤腳本與源代碼,查看運行結果正不對。假設這兩者調試過程是分離的,調源代碼時不能看腳本,或調腳本時不能看被測變量,其操作過程必定很痛苦。
當測試承擔起調試職責,兩者合二為一,交叉影響的問題即自己主動解決。實事上,大家把測試當測試、調試當調試,非常大程度上是由于沒把測試腳本也看作產品代碼,不把它當成產品固有部件,假設觀念轉變過來了,測試腳本也是代碼,調試腳本就是調試代碼,兩者本應合二為一的。當然,還存在工具的問題,缺少好工具,將兩者強扭一起終于仍會不歡而散。
4GWM嘗試讓測試工具承擔起90%的調試工作,全然替換并不是必要。假設測試工具能承擔大部分調試,開發大循環就能拉通了。下圖是開發與測試尚未拉通,是孤立兩個過程的情況:
?
拉通開發大循環后,測試不再是獨立的閉環過程,例如以下圖:
測試設計(即寫腳本)與產品設計(即編碼)融為一體,調試腳本與源代碼成為開發者主要日常工作。上圖的結果評估,對于測試腳本是覆蓋率,對于產品源代碼是其執行表現(其結果可能預期,也可能出差錯了),評估這兩者,再補充用例及完好源代碼,之后進入下一輪迭代循環。
調試通過的腳本打包到測試project,就是可以支持每日構建的用例庫;測試通過的源代碼經release公布,就是在市場上能提供預期功能的正式產品。
4.2.4編碼、調試、測試集成平臺
4GWM在方法論上要求大家把測試腳本也看成產品代碼,以黑盒調測取代大部分單步調試,但方法論是否能順利被實踐支持,還嚴重依賴于測試工具的品質。為此,4GWM要限定測試工具必須將編碼、調試、測試集成到一個平臺。
該要求實際限定測試腳本要擁有與源代碼一樣的權益,因為歷史原因,各主流語言的集成開發環境總是讓代碼能在同一平臺下編輯、調試的,如今既然把腳本也看成一種代碼,就應該賦予它同等權益。拿通俗的話來講,我們要構造一種集成平臺,集編碼、調試、測試于一身,是為了讓“測試”這個后媽晉升級為親媽,原先“調試”是親媽,占盡天時地利,最好還是從IDE讓出一些位置。
把調測一體化平臺作為4GWM特征之中的一個明白下來,能夠防止4GWM在不同編程語言及不同測試工具下實施走樣。請注意,集成平臺的規定不是4GWM本質方法論,但4GWM對工具化支持有比較高要求,配套工具要有足夠的功能,能讓廣大開發者隨心所欲的使用測試手段替代調試。
4.3持續測試
4GWM第三個關鍵域是持續測試,包含3個關鍵特征:
2????? 測試設計先行
2????? 持續保障信心
2????? 重構測試設計
4.3.1測試設計先行
測試先行是XP典型實踐,XP中的測試先行是Test Driven Development(TDD),4GWM規定的測試先行是Test Design First(TDF),兩者主體內容應該一致,細節要求稍有差異。
為方便大家理解,我們還是從XP的TDD基礎上介紹4GWM的TDF。TDD是測試驅動開發,測試代碼在產品代碼之前編寫,要求產品先能測試,然后在解決這個問題過程中補充設計或完好設計。一個簡單的TDD樣例,比方我們要編寫一個函數GetHash計算某對象的hash值,定義GetHash函數的原型后,即開始設計用例,如:
// 確定函數原型
int GetHash(void *obj)
{
??? assert(0,”Not define yet.”);
}
?
// 設計用例
assert( GetHash(newObject(12)) == 12 );
assert( GetHash(newObject(”AName”)) == 63632 );
上述測試肯定通只是,所以要解決這個問題,先是整形對象的hash值算不正確,我們在GetHash函數中加入處理分支:
int GetHash(void *obj)
{
??? if ( ObjType(obj) == dtInt )
??? {
??????? ...
??????? return iHash;
??? }
??? assert(0,”Not define yet.”);
}
然后,再次執行用例發現字串對象的hash值也不正確,再加入對應處理代碼。
TDF也按上述模式操作,但相比TDD稍有差異,主要表如今:
1.???????? TDD強調測試驅動開發,即:測試先做,然后在測試主導下完好被測系統。而TDF僅僅是要求測試設計先做,并不強制測試代碼總比被測功能先跑起來。
TDD要求一開始就寫規范的用例,而TDF很多其它的是讓調試環境先跑起來,調測代碼既能夠是規范的用例,也能夠是待整理的腳本,即草稿狀態的用例。
2.???????? TDD更傾向于自頂向下的開發模式,TDF則較少受此限制,實際操作時,使用最多的是混合模式。即:假設自頂向下比較easy操作,就自頂向下先設計用例,假設自頂向下不好操作,先自底向上先寫底層代碼也無妨。
TDF通常採用三文治操作模式,即:先設計少量用例,讓調測環境順利跑起來,接著補充功能代碼,最后再添加用例使新寫的代碼能完整測試。由于功能編碼夾在中間,成為三文治的餡,過程的兩端都是用例設計。由于結構化設計的緣故,TDF三文治模式也是層層嵌套、依次深入的,先寫高層次測試腳本,接著高層次編碼,然后補充高層次測試設計,之后進入下一層結構化設計,相同先設計下層測試腳本,接著下層功能編碼,再補充下層測試設計。
3.???????? TDF要求盡可能高效的編寫用例,調試操作能夠轉化成用例,已測試通過的功能也能夠在用例中重用,TDD對此沒有特別要求。
TDD與TDF都強調盡可能在編碼之前設計用例,看得到代碼后編寫用例easy墜入慣性思維陷阱,比方,某個被測函數少了一個分支處理,看自己寫的代碼做測試,也相同easy忽略這個分支。所以,先寫腳本后寫代碼能夠檢驗設計是否合理,這時測試設計根據的是規格。
測試先行經XP實踐論證,總體是可行的, Boby George與Laurie Williams的統計數據表明(參見《An Initial Investigation of Test Driven Development in Industry》),實施TDD,有87.5%的開發人員覺得能更好理解需求,有95.8%覺得TDD有助于降低bug,78%的人覺得TDD提高了生產率,另外還有92%的人覺得TDD能促進代碼質量,79%的人覺得TDD有助于簡化設計。同一時候,這份統計還表明,有40%開發人員表示採用TDD比較困難,困難主要原因在于看不到代碼情況下先做測試設計,easy讓人無所適從。
TDF在一定程度上克服TDD應用困難的弊端,它并只是于強調測試設計一定先于編碼,但要求先行編寫的測試腳本與代碼能盡早展現功能,或盡早的驗證規格,腳本與代碼一起對等的被設計者用來實施他的意圖——當然,遵循結構化設計原則,越高層越抽象的邏輯應先驗證,越重要的功能也應先驗證。盡早展現功能,也意味著:寫一點測一點、測一點寫一點,一有可展現或可調試的小功能,測試設計總與功能編碼同步跟進的。
4.3.2怎樣持續保障信心
4GWM很強調維持良好的客戶體驗,在線測試保證白盒測試所見即所得,人性化操作催生快感,拉通測試小循環與開發大循環,使工作效率大幅提高,強化了這樣的快感,如今再加一條:測試過程可度量,讓開發人員至始至終都對自己的代碼充滿信心,鞏固快感使個體愉悅延伸到團隊愉悅。
白盒測試最重要的度量指標是覆蓋率,包含語句覆蓋、分支覆蓋、條件覆蓋、組合條件覆蓋、路徑覆蓋、數據流覆蓋等。設計測試度量標準,不是種類越多就越好,也是越高標準(如路徑覆蓋、MCDC覆蓋)就越好,最重要的是,要恰如其分,另外還得考慮現實因素:測試工具能不能支持。尤其在持續測試模式下,恰當的選擇覆蓋指標尤顯重要,要求過高使測試成為累贅,必定讓持續測試做不下去。與一次測試不同,不恰當覆蓋指標帶來的負面影響,在持續迭代中放大了,稍過復雜就帶來非常大傷害。
實踐經驗表明,常規的白盒測試拿語句覆蓋與分支覆蓋度量已經足夠,對于局部邏輯復雜的代碼,再增設MCDC覆蓋就夠用了。4GWM推薦把調用覆蓋(近似于語句覆蓋)當作主要測試指標,調用覆蓋是觀察函數調用與被調用關系的一種覆蓋指標,由于4GWM以函數為單位關注測試過程,函數是識別不同測試及同一測試中不同分層的根據,以調用關系度量測試程度,是這樣的基于調用接口、灰盒模式的測試方法論自然延伸。
除了覆蓋率指標,我們還得差別經意測試與不經意測試。例如測試某特定分支設計一個用例,除了你期望的分支跑到外,同一函數中其他部分的某些分支也能跑到,這是不經意產生的覆蓋率貢獻。不經意測試使結果評估產生偏差,也給想偷懶的員工帶來便利,例如,測試某通信產品,設計用例打一個電話,就可能貢獻20%的覆蓋率。
為避免上述情況,4GWM設計出還有一指標:測試設計程度(或稱用例覆蓋度),該指標分析測試project中,被測函數調用次數與該函數分支總數的關系。一個函數分支越多,就應設計很多其它的用例來測試它。用例覆蓋度是作為基礎條件參與測試評估體系的,設置門檻閥值,過了門檻條件,即使多設計用例也不給測試效果加分,但沒過門檻,結果評估則是一票否決的。
4GWM要求測試工具以直觀、簡潔的方式隨時統計測試程度。由于是增量式設計,被測代碼與測試腳本都按對等速度遞增的,測試評估先要求定義測試觀察范圍,選中當前關注的被測源文件與腳本文件,成為測試project,然后,工具始終以project為單位進行評估,在主操作界面顯示一個標志燈,亮紅燈表示當前測試未通過,有bug等待先解決,亮黃燈表示測試通過了但覆蓋率指標不符合要求,亮綠燈表示滿足覆蓋指標而且測試通過。
遵循4GWM的軟件開發過程,就是時時刻刻要讓界面綠燈亮起的持續開發過程,這好比開車,功能編碼是踩油門,測試編碼是踩剎車,界面紅綠燈是執法標準,僅僅亮綠燈才干往前走。規則已經非常清晰了,時時刻刻遵守交規就是持續信心的保障。
4.3.3重構測試設計
做好人不難,難就難在一輩子都做好人(做壞人更難?沒見過一輩子僅僅做壞事的人)。我們照章開車,沒人給你開罰單,但不意味著項目就沒問題了,方向走反了是南轅北轍,方向偏了可別指望歪打正著。相同,要讓白盒測試能持續的跟進,非常重要一點,測試設計要能高速重構。軟件設計總是難免出錯,其實,多數產品開發都會經歷幾次局部重構,當被測代碼大幅調整,規模與之對等的測試代碼怎樣高速修正成了迫切待解決的難題。
重構測試設計要根據被測代碼,測試工具應保存近期綠燈狀態時的源代碼信息,比方,系統中都有哪些全局符號(變量、函數),符號是什么類型,被測函數都調用哪些子函數、都使用哪些全局變量等。重構測試設計時,根據歷史被測代碼與重構后代碼的差異,自己主動分析當前哪些用例會受影響,怎樣影響,再詳細指出哪些腳本行應作調整。這好比開車走錯路,要回頭想想在哪個十字路口開始錯的,錯在哪個方向。當上述過程有工具幫我們分析,維護用例的效率就高多了。
5結論
眼下,4GWM已有實踐主要集中在C語言測試,在線測試、持續測試諸多實踐非常早就有測試工具支持,已有數年應用積累。本文歸納的4GWM九大特征,都來源于白盒測試長期實踐,先實踐后總結,先有詳細應用,然后歸納出通用方法。
這里再總結一下,上文介紹的3個關鍵域中,在線測試是基礎,是維持良好客戶體驗的第一步,在線測試不僅拉通測試小循環,初步解放生產力,并且,在線特性讓灰盒調測成為可能。灰盒調測拉通開發大循環,再次大幅度解放生產力。當測試效率兩度提升后,持續集成就不再困難了。
?
參考資料
1. E. Michael Maximilien, "Assessing Test-Driven Development at IBM"
2. Joel Spolsky, "Joel On Software"
3. Elfriede, D. "Effective Software Testing:
50 Specific Ways to Improve your Testing"4. George, B. and Williams, L., "An Initial Investigation of Test-Driven Development in Industry"
5. Wayne Chan, "VcTester User Manual"
6. Philip M. Johnson, and Joy M. Agustin, "Keeping the coverage green: Investigating the cost and quality of testing in agile development"
7. IPL Information Processing Ltd, "Why Bother to Unit Test?"
?
=================? END?=============================
?本專題相關的文章:
?第4代白盒測試方法介紹--理論篇
?第4代白盒測試方法介紹--VcTester實踐篇
?第4代白盒測試方法通俗釋義
?
?第4代白盒測試方法之“為什么要做白盒測試”
?第4代白盒測試方法之“企業怎樣推行白盒測試”
?第4代白盒測試方法之“實施白盒測試的幾個誤區”
?第4代白盒測試方法之“怎樣選擇嵌入式白盒測試工具”
?
?第4代白盒測試方法實踐之“VcTester持續集成框架的應用價值”
?第4代白盒測試方法實踐之“使用VcTester實施持續集成的組織管理模式”
?第4代白盒測試方法實踐之“怎樣在VcTester集成自己主動構建功能”
?第4代白盒測試方法實踐之“使用VcTester構造持續集成及每日構建平臺”
?第4代白盒測試方法實踐之“內存泄露檢查工具VLD怎樣與VcTester配合使用”
?第4代白盒測試方法實踐之“怎樣將Pclint嵌入到VcTester中使用”
?第4代白盒測試方法實踐之“VcTester插裝原理與各種覆蓋率配置”
?
通信軟件白盒測試的三種境地
?
?
?轉載于:https://www.cnblogs.com/blfshiye/p/4374254.html
總結
以上是生活随笔為你收集整理的第4代白盒測试方法介绍--理论篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU 2822 Dogs【两次bfs】
- 下一篇: centos 7.0 ln命令 和chk