從用例到測(cè)試用例
每個(gè)入口點(diǎn)都必須與相應(yīng)的用例匹配。某些情況下可以忽視這一步,因?yàn)轭?lèi)名的自記錄可以實(shí)現(xiàn)自動(dòng)匹配,比如Saxon中的轉(zhuǎn)換類(lèi)可以實(shí)現(xiàn)XSL轉(zhuǎn)換,查詢(xún)類(lèi)可以進(jìn)行XQuery轉(zhuǎn)換。
其它情況則要復(fù)雜得多。通常用例描述的功能只能以橫切關(guān)注點(diǎn)的方式存在,不能用任何單獨(dú)的類(lèi)進(jìn)行例證。只有幾組類(lèi)交互時(shí)或滿(mǎn)足一定條件時(shí),才能觀察到功能行為。這種情況下,測(cè)試的初始化程序會(huì)比較長(zhǎng),或者可以用setUp()方法提供需要的測(cè)試環(huán)境。
而調(diào)用代碼的運(yùn)行程序應(yīng)該盡可能地設(shè)計(jì)成一行,以減少與被測(cè)試代碼的關(guān)聯(lián),這可以有效避免對(duì)邊緣效應(yīng)與不穩(wěn)定實(shí)現(xiàn)細(xì)節(jié)的依賴(lài)。測(cè)試的檢查階段是復(fù)雜的,因?yàn)檫@個(gè)階段經(jīng)常需要添寫(xiě)非測(cè)試用代碼。測(cè)試時(shí)可能需要對(duì)結(jié)果進(jìn)行嚴(yán)格的分析以確保其符合要求。有時(shí)甚至需要將這個(gè)過(guò)程分為幾步來(lái)完成,以取得測(cè)試可以識(shí)別的結(jié)果。在XSL轉(zhuǎn)換中,這兩種情況都是可能的,結(jié)果儲(chǔ)存在文件中,然后以XML格式讀入內(nèi)存并進(jìn)行準(zhǔn)確性分析。
Saxon中有個(gè)相對(duì)簡(jiǎn)單的例子。已有XML文件和XPath表達(dá)式的情況下,Saxon可以執(zhí)行表達(dá)式并返回匹配列表。Saxon中的XpathExample樣本類(lèi)是用來(lái)執(zhí)行這種任務(wù)的。基于以上分析,可以設(shè)計(jì)如下的測(cè)試流程:
public void testXPathEvaluation() {
//initialize
XPathEvaluator xpe = new XPathEvaluator(
new SAXSource(new InputSource("/path/to/file.xml")));
XPathExpression findLine =
xpe.createExpression("/some/xpath[expression]");
//work
List matches = findLine.evaluate();
//check
assertTrue(matches.count() > 0);
}
兩次輸入的都是字符串常量,輸出的則是所匹配的列表,可以用來(lái)驗(yàn)證匹配結(jié)果的正確性。這些工作都由一行代碼完成,這行代碼只是簡(jiǎn)單地調(diào)用了被測(cè)試的方法。
另一種可能的情況是XPathEvaluator沒(méi)有調(diào)用createExpression()方法。因?yàn)楸磉_(dá)式不存在,這時(shí)可能會(huì)顯示錯(cuò)誤信息。
將輸入的源文件名和表達(dá)式保留在測(cè)試用例中不是個(gè)好習(xí)慣。某些項(xiàng)目(服務(wù)器名、用戶(hù)名和密碼等)不應(yīng)該出現(xiàn)在測(cè)試文件中,它們應(yīng)該可以根據(jù)情況自由設(shè)置。并且,測(cè)試用例的設(shè)計(jì)應(yīng)該方便測(cè)試驅(qū)動(dòng)和測(cè)試數(shù)據(jù)的分離、測(cè)試驅(qū)動(dòng)對(duì)大范圍數(shù)據(jù)的可重用性和測(cè)試數(shù)據(jù)對(duì)測(cè)試驅(qū)動(dòng)的可重用性。另一方面,不要將一個(gè)簡(jiǎn)單的測(cè)試用例實(shí)現(xiàn)設(shè)計(jì)地過(guò)于復(fù)雜。一般來(lái)說(shuō),測(cè)試用例已經(jīng)說(shuō)明了系統(tǒng)的大部分狀態(tài),并可對(duì)其進(jìn)行參數(shù)描述,所以無(wú)需在測(cè)試中進(jìn)行過(guò)于詳細(xì)的參數(shù)描述。
許多代碼段可能出現(xiàn)在不止一個(gè)測(cè)試用例中。有經(jīng)驗(yàn)的面向?qū)ο箝_(kāi)發(fā)人員會(huì)嘗試對(duì)其進(jìn)行重構(gòu)并創(chuàng)建通用類(lèi)和有效方法。有時(shí)候這樣做非常有用,比如登錄過(guò)程應(yīng)該設(shè)計(jì)成所有測(cè)試用例可用的方法。 但是,不要過(guò)度設(shè)計(jì)測(cè)試,這些Java類(lèi)僅僅是用來(lái)驗(yàn)證應(yīng)用程序的功能行為而已。
測(cè)試用例是脆弱的。比如,如果開(kāi)發(fā)人員更改了testXPathEvaluation測(cè)試中輸入文件的位置,或者creatExpression方法簽名有所變動(dòng),測(cè)試腳本會(huì)失效。
對(duì)于應(yīng)用程序的測(cè)試用例實(shí)現(xiàn)來(lái)說(shuō),大量的重復(fù)性工作與改動(dòng)是不可避免的。因此,可跟蹤性對(duì)于所有的測(cè)試用例都是至關(guān)緊要的。出現(xiàn)問(wèn)題的時(shí)候,如果能為開(kāi)發(fā)人員指出相應(yīng)的測(cè)試用例說(shuō)明和用例說(shuō)明將有利于提高修正bug的速度。
因此,測(cè)試用例注釋中應(yīng)標(biāo)明原始說(shuō)明文檔的引用位置。這可以是一個(gè)簡(jiǎn)單的代碼注釋?zhuān)部梢詫?duì)每條測(cè)試都注釋相關(guān)用例和所測(cè)功能,這樣當(dāng)測(cè)試出現(xiàn)問(wèn)題時(shí)開(kāi)發(fā)人員會(huì)收到一條相關(guān)信息。因此,在代碼中加入?yún)⒖疾⒕S護(hù)可追蹤性是很重要的。
設(shè)計(jì)運(yùn)行時(shí)事件表
要了解測(cè)試覆蓋的范圍,必須先了解所測(cè)試代碼如何運(yùn)行,以及各種靜態(tài)類(lèi)如何形成描述程序狀態(tài)的動(dòng)態(tài)對(duì)象圖表。
有許多模擬這種行為的方法,包括Granovetter圖和物件互動(dòng)圖。其基本思想是用圖形化的方式研究代碼以了解測(cè)試中涉及到的運(yùn)行時(shí)部分。這些技術(shù)都可用運(yùn)行時(shí)事件表(Runtime Event Diagrams)來(lái)描述,因?yàn)檫@些圖表顯示了程序運(yùn)行時(shí)發(fā)生的事件,而非理論上類(lèi)可以控制的事件。這些圖表非常重要的原因包括:
首先,這些圖表便于從高層上理解代碼,并提供有用的說(shuō)明文檔。這個(gè)文檔與代碼的內(nèi)聯(lián)文檔不同。這些圖表顯示代碼的運(yùn)行時(shí)表現(xiàn),是產(chǎn)生代碼功能的地方,也易于對(duì)系統(tǒng)的了解;大多數(shù)設(shè)計(jì)模式和架構(gòu)在用對(duì)象和參考表示時(shí)要比用類(lèi)和域表示容易得多。
另外,這些圖表將測(cè)試執(zhí)行的代碼分類(lèi)列表,并確定測(cè)試是否會(huì)受到將來(lái)對(duì)任意代碼改動(dòng)的影響。如果開(kāi)發(fā)人員確定測(cè)試A是建立在B、C和D的基礎(chǔ)上,她可以確定如果對(duì)B、C或D做出改動(dòng)需要對(duì)A進(jìn)行重新測(cè)試(確保向后兼容)。
以盡可能少的步驟模擬系統(tǒng)是個(gè)好方法?偟膩(lái)說(shuō),實(shí)際調(diào)用與此無(wú)關(guān),重要的是系統(tǒng)如何作為整體運(yùn)作以獲得預(yù)期目標(biāo)。可以用簡(jiǎn)化的模擬系統(tǒng)實(shí)現(xiàn)這個(gè)目的,該系統(tǒng)只關(guān)心對(duì)象間的基本交互,并用自然語(yǔ)言描述交互中發(fā)生的事件。
做出運(yùn)行時(shí)事件表后,可以將其整合到類(lèi)文檔中。需要注意的是,為表添加一些限制可使其對(duì)類(lèi)的修改更有彈性。首先,一般不能使用方法名,因?yàn)樗鼈儠?huì)隨時(shí)間發(fā)生變化。取而代之的是更易理解的自然語(yǔ)言描述。其次,這些圖表主要是關(guān)于系統(tǒng)中各部分的交互。這是高層架構(gòu)上的設(shè)計(jì)方案,一般不會(huì)再做改動(dòng)。后,圖表是建立在類(lèi)型而非特定類(lèi)的基礎(chǔ)上。只要基本類(lèi)型不變,為維持交互協(xié)議的正常運(yùn)行,這些圖表不需要更新。
一旦圖表創(chuàng)建成功,可以在許多方面獲得應(yīng)用。比如,一個(gè)圖表可以用來(lái)獲取系統(tǒng)如何運(yùn)作,以及如何運(yùn)用其交互部件實(shí)現(xiàn)功能的概覽。在某種程度上這是一種簡(jiǎn)化了的UML語(yǔ)言,它只描述關(guān)系到整體功能的系統(tǒng)部件:實(shí)例及其類(lèi)型、其它引用的實(shí)例,以及組件可以實(shí)現(xiàn)的功能。
這些圖表也可以用來(lái)分析系統(tǒng)的復(fù)雜性以及如何進(jìn)行簡(jiǎn)化。要確定簡(jiǎn)化系統(tǒng)的方法,可以查找系統(tǒng)中使用過(guò)一到兩次的對(duì)象,并為其尋找其它可能更合適的位置。也可以查找重復(fù)的任務(wù),將其封裝到方法或類(lèi)中。
然而,重要的是圖表在測(cè)試中的應(yīng)用。通過(guò)對(duì)系統(tǒng)狀態(tài)的總結(jié),圖表可以幫助解決系統(tǒng)中出現(xiàn)的問(wèn)題。出現(xiàn)問(wèn)題時(shí),圖表中的信息便可用作參考。因?yàn)橹恍枰獙⑾到y(tǒng)目前狀態(tài)與預(yù)期狀態(tài)作比較即可,這樣確定問(wèn)題產(chǎn)生的原因也變得比較簡(jiǎn)單了。對(duì)小組件的改動(dòng)不應(yīng)該影響整體架構(gòu),因此可以通過(guò)對(duì)照運(yùn)行時(shí)事件表以保證系統(tǒng)仍然正常運(yùn)行。并且,當(dāng)有重要組件發(fā)生變動(dòng)時(shí),可以用運(yùn)行時(shí)事件表對(duì)照系統(tǒng)當(dāng)前狀態(tài)以獲取系統(tǒng)修正方案。由于將系統(tǒng)作為整體和對(duì)預(yù)期功能的描述,運(yùn)行時(shí)事件表也可以看作是一種結(jié)構(gòu)化的單元測(cè)試。如果系統(tǒng)有變動(dòng),可以更容易地做出修正以維持系統(tǒng)的正常功能。
如果經(jīng)常因細(xì)節(jié)問(wèn)題影響對(duì)全局的把握,應(yīng)該使用圖表。其高層本質(zhì)可以用來(lái)分析軟件的設(shè)計(jì)模式,像反模式一樣。還有許多其它用途,并且當(dāng)運(yùn)行時(shí)事件表、測(cè)試用例說(shuō)明和用例說(shuō)明沒(méi)有描述所需的細(xì)節(jié)時(shí),它還提供了直接進(jìn)行代碼分析的路線(xiàn)圖。
利用功能測(cè)試進(jìn)行回歸測(cè)試
后,為回報(bào)你在功能測(cè)試上做出的努力,配置一個(gè)與自動(dòng)生成的程序相應(yīng)的自動(dòng)化測(cè)試程序。這個(gè)程序不只從功能上測(cè)試代碼,還可以同時(shí)進(jìn)行常規(guī)的回歸測(cè)試。現(xiàn)在大多開(kāi)發(fā)項(xiàng)目都建立在龐大的代碼庫(kù)基礎(chǔ)上,如果不能對(duì)代碼庫(kù)進(jìn)行充分測(cè)試,開(kāi)發(fā)團(tuán)隊(duì)將無(wú)從決定對(duì)程序的修正是否會(huì)破壞現(xiàn)有的功能,結(jié)果是很難對(duì)這種代碼進(jìn)行擴(kuò)展或優(yōu)化。與此相反,如果開(kāi)發(fā)人員可以在全面的功能測(cè)試基礎(chǔ)上進(jìn)行回歸測(cè)試,優(yōu)化或擴(kuò)展代碼時(shí)不必?fù)?dān)心可能會(huì)引發(fā)不可預(yù)料的問(wèn)題。畢竟,沒(méi)有比做完回歸測(cè)試后發(fā)現(xiàn)一切正常更令人心情愉快的事了。