比如,Saxon有一小組類作為邏輯入口點提供對庫的訪問。通過對外部類進行編碼操作,比如轉換、設置和查詢,客戶端代碼可以訪問庫的許多功能類,而無需考慮類的接口問題,甚至無需擔心這些類是否存在。這些外部類用高層易用的接口提供一個簡單的方式對系統功能進行測試,這正是一個優良的庫的特征。
程序代碼中的各個功能模塊通常是各自獨立的。在某些代碼中,甚至可以認為這些模塊各自對應不同的、可通過大量外部類訪問的庫。這些類查找高層接口的邏輯位置。插件結構通常都采用這種設計模式:每個插件程序都有一個可以有效執行內部代碼全部功能的簡單接口。
在一些非嚴格描述的系統中,通常有一個所有程序行為的中介點。在MVC架構中,這個中介類一般作為“控制器”,負責配置系統各部分的請求路由。整體系統的功能主要由這個控制器連接的類實現,因此,這些類是測試的主要對象。
比如在 Applet程序設計中,java.applet.Applet的派生類就是所有代碼的中心處理單元。根據代碼的分解程度,測試焦點可以放在Applet 子類或與其連接的類上。
連接各個模塊的代碼也是測試的主要對象。將應用程序請求轉換為數據庫查詢的類,以及有相似功能的適配類是其次應該考慮的測試對象。
各種基于MVC(模式-視圖-控制器)架構的組件可以用其它的測試框架(比如Junit的擴展)進行測試。例如,Struts的 action類就最好使用JUnit的擴展StrutsTestCase進行測試;服務器端的組件(如Servlets、JSP和EJB)最好用 Catus進行測試;而HttpUnit則是對Web應用程序進行黑盒測試的最好框架。本文討論的所有技術都可應用于這些框架環境下的測試。
從用例到測試用例
每個入口點都必須與相應的用例匹配。某些情況下可以忽視這一步,因為類名的自記錄可以實現自動匹配,比如 Saxon中的轉換類可以實現XSL轉換,查詢類可以進行XQuery轉換。
其它情況則要復雜得多。通常用例描述的功能只能以橫切關注點的方式存在,不能用任何單獨的類進行例證。只有幾組類交互時或滿足一定條件時,才能觀察到功能行為。這種情況下,測試的初始化程序會比較長,或者可以用 setUp()方法提供需要的測試環境。
而調用代碼的運行程序應該盡可能地設計成一行,以減少與被測試代碼的關聯,這可以有效避免對邊緣效應與不穩定實現細節的依賴。測試的檢查階段是最復雜的,因為這個階段經常需要添寫非測試用代碼。測試時可能需要對結果進行嚴格的分析以確保其符合要求。有時甚至需要將這個過程分為幾步來完成,以取得測試可以識別的結果。在XSL轉換中,這兩種情況都是可能的,結果儲存在文件中,然后以XML格式讀入內存并進行準確性分析。
Saxon中有個相對簡單的例子。已有XML文件和XPath表達式的情況下,Saxon可以執行表達式并返回匹配列表。Saxon中的XpathExample樣本類就是用來執行這種任務的?;谝陨戏治?,可以設計如下的測試流程:
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);
}
兩次輸入的都是字符串常量,輸出的則是所匹配的列表,可以用來驗證匹配結果的正確性。這些工作都由一行代碼完成,這行代碼只是簡單地調用了被測試的方法。
另一種可能的情況是XPathEvaluator沒有調用createExpression()方法。因為表達式不存在,這時可能會顯示錯誤信息。
將輸入的源文件名和表達式保留在測試用例中不是個好習慣。某些項目(服務器名、用戶名和密碼等)不應該出現在測試文件中,它們應該可以根據情況自由設置。并且,測試用例的設計應該方便測試驅動和測試數據的分離、測試驅動對大范圍數據的可重用性和測試數據對測試驅動的可重用性。另一方面,不要將一個簡單的測試用例實現設計地過于復雜。一般來說,測試用例已經說明了系統的大部分狀態,并可對其進行參數描述,所以無需在測試中進行過于詳細的參數描述。
許多代碼段可能出現在不止一個測試用例中。有經驗的面向對象開發人員會嘗試對其進行重構并創建通用類和有效方法。有時候這樣做非常有用,比如登錄過程應該設計成所有測試用例可用的方法。 但是,不要過度設計測試,這些Java類僅僅是用來驗證應用程序的功能行為而已。
測試用例是脆弱的。比如,如果開發人員更改了testXPathEvaluation測試中輸入文件的位置,或者creatExpression方法簽名有所變動,測試腳本就會失效。
對于應用程序的測試用例實現來說,大量的重復性工作與改動是不可避免的。因此,可跟蹤性對于所有的測試用例都是至關緊要的。出現問題的時候,如果能為開發人員指出相應的測試用例說明和用例說明將有利于提高修正bug的速度。
因此,測試用例注釋中應標明原始說明文檔的引用位置。這可以是一個簡單的代碼注釋,也可以對每條測試都注釋相關用例和所測功能,這樣當測試出現問題時開發人員就會收到一條相關信息。因此,在代碼中加入參考并維護可追蹤性是很重要的。
設計運行時事件表
要了解測試覆蓋的范圍,必須先了解所測試代碼如何運行,以及各種靜態類如何形成描述程序狀態的動態對象圖表。
有許多模擬這種行為的方法,包括Granovetter圖和物件互動圖。其基本思想是用圖形化的方式研究代碼以了解測試中涉及到的運行時部分。這些技術都可用運行時事件表(Runtime Event Diagrams)來描述,因為這些圖表顯示了程序運行時發生的事件,而非理論上類可以控制的事件。這些圖表非常重要的原因包括:
首先,這些圖表便于從高層上理解代碼,并提供有用的說明文檔。這個文檔與代碼的內聯文檔不同。這些圖表顯示代碼的運行時表現,是產生代碼功能的地方,也易于對系統的了解;大多數設計模式和架構在用對象和參考表示時要比用類和域表示容易得多。