單元測試和靜態分析通常被看作是有助于確保程序的正確性的互不相干的方法。本文研究了這兩種方法之間的關系,并討論了構成每種方法工作構架的工具如何相得益彰。特別地,Eric Allen 討論了一些可用而又令人興奮的新應用程序,這些應用程序允許您進一步提升您的單元測試。 這是一場古老的爭論 — 哪種方法對產生健壯代碼更有價值:測試還是靜態分析和驗證?您會在程序員的日常工作中聽到這種爭論,尤其是在極端編程(Extreme Programming)CC%B3');" target="_self">論壇上。(請參閱我們由 Roy Miller 主持的 XP 論壇。) 支持靜態分析(包括類型檢查)的主要論據是:其結果適用程序所有可能的運行,而通過單元測試只能保證被測試的組件(在測試它們的平臺上)只適用測試組件的特定輸入。 支持單元測試的主要論據是它更容易處理。您可以測試程序的許多約束,這些約束遠遠超出了同期的靜態分析工具所能達到的范圍。 請允許我在此冒昧地說一句:我認為將這兩種工具看作對立的是一個錯誤。每種工具都有助于構建更健壯的程序。實際上,它們可以通過非常強大的方式進行互補。 每種工具都有各自的長處,對于補充另一種工具特別有用:
讓我們研究這其中的每個屬性,并討論一些可幫助您將其長處帶給其它方法的工具。 顯示常用執行路徑的單元測試 還有另一種方法,其中單元測試可以是一種可執行的文檔形式。在從單元測試的運行中從特殊到一般地推斷出推測性不變量之后,分析工具可以嘗試從一般到特殊地驗證不變量的存在,或者它可以利用可在運行時檢查的斷言注釋該代碼。 在任何一種情況下,在該工具做任何其它工作之前,最好向用戶返回推測的不變量集的報告,以詢問用戶真正想要哪些不變量。順便提一下,如果此類工具向用戶報告了許多他們不想要的不變量,這可能是單元測試出了問題的信號 — 例如,它們不夠一般。 可用這種方式與單元測試一起使用的工具是 Daikon,它是一款來自 MIT 的 Mike Ernst 的程序分析小組的免費的、試驗性的工具。Daikon 分析程序的運行(例如單元測試的運行),并嘗試推測不變量。然后它詢問用戶是否想要這些不變量,并將用戶想要的不變量作為斷言插入程序。 例如,假定我們編寫一個向量(Vector)的適配器,該適配器實現接口 假定該數組的長度存儲在字段 | |
clearcase/" target="_blank" >cccccc height=17>import junit.framework.TestCase;
public class VectorAdapterTest extends TestCase { | |
然后我們可以實現我們的適配器以通過這個測試,如下所示: | |
import java.util.Vector;
public class VectorAdapter implements Sequence { interface Sequence { | |
當 Daikon 在這段代碼上運行時,它可能推斷:對于方法 然后程序員可以檢查 Daikon 報告的不變量,從而更好地了解其測試覆蓋程序的范圍到底怎么樣。例如,如果 Daikon 開始推斷出大量不想要的不變量,這意味著單元測試只是用不具代表性的可能的程序輸入的子集檢測了程序。 盡管 Daikon 是用 Java 語言編寫的,但它需要用 C++ 編寫的前端,這削弱了它原有的可移植性。盡管如此,還是可以在線獲得針對許多主要平臺的前端構建。此外,Daikon 團隊也打算添加其它平臺所需要的構建。 (您可以在參考資料一節找到關于 Daikon 的下載信息和更多內容。) 可以檢查單元測試覆蓋范圍的分析工具
目前有幾種試圖自動從代碼產生單元測試的免費工具,但大多數擔任這項任務的免費工具還處于起步階段。其中一些比較有希望的是 JUnitDoclet 和 JUB(“JUnit test case Builder”的縮寫),可在 SourceForge 上得到它們(參考資料一節提供了它們的鏈接)。 關于這些類型的工具,要牢記的要點是:最適宜應用于通過測試更新舊代碼。當構建新項目時,它們的作用不大。 為什么會這樣呢?因為新項目應該與項目上的單元測試是一前一后構建的。開發單元測試是構建設計的強有力的方法;針對組件的 API 就是在編寫測試時隱式地為它們設計的。此外,以這種風格進行設計向設計師提供了即時的反饋。糟糕的設計將非常難于編寫測試!并且,任何分析工具在確定為程序編寫什么測試這方面,都很難做得象設計師那樣好。 第二種分析工具分析程序及其單元測試,并確定測試能在多大范圍內覆蓋程序。與剛才提到的第一類工具不同,此類工具對每個項目都是有用的。實際上,極端編程團隊可以考慮將此類工具集成到他們的代碼提交過程中。那么,他們不僅能夠防止代碼在通過所有測試之前被提交,而且可以防止代碼在未經測試的情況下提交!不僅懶惰會導致測試覆蓋范圍偏小,錯誤也可能導致同樣后果,因此,此類強制措施對任何技能(和完整性)級別的程序員都有用。 Clover 是一種可以執行此類分析的新的并且特別有希望的工具。Clover 是 Ant 的插件,Ant 是 Clover 分兩階段過程進行工作。首先,它在編譯時檢測代碼。然后,在測試時將有關測試的運行信息寫到用來生成報告的數據庫中(通過 GUI、網頁或在控制臺中)。 將 Clover 集成到使用 Ant 的現有項目中很簡單。這涉及調整項目的 build.xml 文件以添加幾個在編譯、記錄測試和生成報表期間檢測代碼的目標。例如,假定我們有一個帶構建和編譯目標的 build.xml 文件。我們所必須做的全部工作是將 Clover JAR 文件放到我們的 Ant 庫目錄中,并如下所示擴展 build.xml 文件(Clover 用戶指南中提供了這些和類似于 Ant 目標的信息;為了方便,我在這里包括了它們): | |
<property name="clover.initstring" value="/tmp/mycoverage.db"/>
<target name="with.clover"> <path id="clover.classpath"> <target name="clover.report"> | |
特性 在上面的代碼中,我們將生成 HTML 報告。我們也可以生成文本報告(對于提供給腳本以確定測試的覆蓋范圍是否可接受非常有用)和基于 Swing 的報告。 設置 | |
$ ant with.clover compile test $ ant clover.report | |
就是這么簡單。請查閱流行的編碼工具 JBoss 和 Ant 的在線 Clover 報告,以獲取一些樣本輸出。(您可以在參考資料一節找到更多有關這些內容的下載信息和其它信息。) 兩種方法的結合 將來,其它工具可能會提供更強有力的單元測試能力。例如,類型推斷(type-inference)引擎和優化編譯器可以從現有的單元測試推斷線索、UML 生成工具可以從測試構造各種圖表(不僅是類圖)等等。對于合并這些方法以獲得更佳的代碼構建和故障診斷而言,還存在著巨大的空間可以進行創造性開發和實驗。 請記住每種方法的屬性及其長處:
每種方法的長處都可以用來彌補另一種方法的潛在弱點。 下一次,我們將研究增強的單元測試的另一條路徑,并了解一些最新的工具,它們可用于幫助您在 GUI 上開發單元測試。
|
原文轉自:http://www.anti-gravitydesign.com