對于許多團隊來說,單元測試現在是開發過程的一個主要部分;JUnit 之類的框架可以進行無損測試,盡管我們并不喜歡它,寧愿為某些 代碼編寫某些 測試。單元測試運行效率很低,只能測試單個代碼片段,并且,一般情況下,測試代碼的重用性通常很也低 —— 昨天為組件 A 編寫的測試不能很好地用于測試組件 B(示例代碼除外)。
典型的單元測試場景
在發現 bug 時,要做的第一件事是什么?您可能只是想去修復它,但是,在長時間的運行中,這不是一個最有效的方法。在許多開發部門中,處理 bug 的過程如下:
- 針對 bug 編寫測試用例
- 確保測試用例在遇到 bug 時運行失敗
- 修復 bug
- 確保測試用例通過
- 確保其他測試套件仍能通過
- 檢查修正和測試用例,形成版本控制
- 將修正記錄在 bug 跟蹤系統中
盡管此方法在短期內比僅修復 bug 要多做許多工作,但它提供了許多更有價值的東西:獲得修復 bug 的更多信心,因為您已經對它進行了測試;獲得 bug 將不會再出現的更多信心,因為測試用例是回歸測試套件的一部分。在版本控制系統和 bug 跟蹤系統之間,還可以獲得一個記錄,該記錄描述了 bug 是什么以及如何修復它 —— 這是非常有用的信息,其他人會從中受益。
如果進取心較強,那么可以思考一下 bug 是怎樣出現的,并在其他位置查找同一錯誤。如果在別處發現同一錯誤,那么可以對這些 bug 進行測試和修復。單元測試作為質量管理工具的主要弱點是每個測試用例只能測試一個代碼片段。因為測試用例是專為每個組件和每個潛在錯誤模式設計的,所以只有編寫足夠多的單元測試才能測試大量的產品,這非常耗時并且代價高昂。
![]() ![]() |
![]()
|
QA 經濟
測試是一種基本的質量管理工具,我們知道僅有多組測試用例還不足以找出復雜軟件片段中的所有 bug。事實上,對于任何優秀程序而言,“查找所有 bug” 是不可能實現的目標。據估計,NASA 向每個開發人員提供了 20 個測試程序(大大超過任何商業實體)來負責質量評價 (QA) —— 但軟件仍有缺陷。因此,質量評價的目標不應是查找所有的 bug,因為這是不可能的。相反,質量評價的目標應該是提高代碼運行良好的信心,從而最大程度地提供可用資源。
要高效運行質量評估量 (QA),則需要對可用 QA 方法中的可用資源做預算,這樣才能最大限度地提高信心。覆蓋范圍大的測試套件可以提高我們對代碼使用的信心,因為它進行了一次徹底的代碼審查。執行兩次比執行一次較果好,因為每次都會發現另一次可能錯過的錯誤。兩次同樣遵循收益遞減規則,所以測試價值為 X 美元和代碼審查價值為 Y 的 QA 計劃要比價值為 X+Y 的任何一次測試或代碼審查的效果好。
添加靜態分析
靜態分析是在不運行代碼的情況下對其進行分析的過程,它與進行前面的代碼審查時我們執行的操作非常相似,或者與標記可疑結構時 IDE 執行的操作非常相似。靜態分析是添加到 QA 混合(QA mix)中的一項優良技術,因為它擅長查找其他方法(如測試和代碼審查)可能錯過的錯誤。靜態分析相對比較容易一些,不像單元測試那樣必須為要測試的每個類重新編寫測試,您可以在任何代碼上運行靜態分析工具。
FindBugs 是一種開放源碼的靜態分析工具,它包含用于許多常見 bug 模式的 bug 模式檢測器,令人驚訝的是,即使在測試良好的軟件中,FindBugs 也常常會發現一些 “沉默” 的 bug,但是單元測試和專業代碼審查都可能錯過這些 bug。FindBugs 還允許編寫新的 bug 模式檢測器,并將它們包裝為插件,所以如果一組標準的檢測器不能按您的需要執行,那么您可以很容易地編寫自已的檢測器。此擴展性使 FindBugs 成為非常強大的質量管理工具,因為當發現新類型的錯誤時,可以針對該錯誤編寫檢測器,并在整個代碼基址中搜索該錯誤。
靜態分析的主要作用是分析輸出,并確定報告的條目是真的 bug 還是假警報。編寫的部分優秀分析工具或 bug 模式檢測器會管理誤報率;核心 FindBugs 包中的檢測器已經進行了調優,目的是使誤報率不超過 50 %,這樣分析輸出時不會有太多的煩麻。(將此閾值與針對 C 的 lint-like 工具進行比較,后者常常發出許多假警報,使用時相當耗時。)
將它提升一個級別
前面描述修復 bug 的方法(首先編寫測試用例,然后檢查修復和測試用例)反映了這樣一個愿望:不僅要修復 bug,還要提高修復它的信心,并記錄如何修復它,以及何時修復它。此方法比僅修復 bug 要多做許多工作,但是它給我們提供了更多的信心,我們的代碼在經過多個開發人員的不斷修改后可以繼續使用。不過,僅為所發現的 bug 編寫測試用例是一種消極方法。在代碼失敗之前,我們希望盡可能以最佳實踐分析代碼。
清單 1 通過 BigDecimal
類說明了常見的 bug。BigDecimal
是固定不變的,所以算術方法(如 add()
)會返回一個新的 BigDecimal
作為其結果,而不修改調用它們的對象。清單 1 中的代碼顯然被假定為有條件地將運輸費用添加到總體訂購價格中,但是,實際上不能隨意添加任何內容,因為 add()
的返回值被丟棄了:
清單 1. 典型的 bug 模式 —— 使用 mutator 方法配置 factory 方法
|
清單 1 中的錯誤是一種常見的錯誤,它忘記了對象是不可變的,從而將 factory 方法誤認為 mutator 方法。如果在代碼中查找此類錯誤,就會發現存在同一錯誤多次發生的情況,因為它來源于對特定庫類工作方式的誤解。對于查找此 bug,負責任的開發人員可能會搜索整個代碼基址來查找對 BigDecimal.add()
、subtract()
等方法的調用,并尋找忽略返回值的其他實例。
此策略是一個好的開頭,但我們可以做得更好。在這里識別 bug 模式是非常容易的 —— 忽略不可變對象上的求值方法(value-bearing method)的結果。識別出該模式后,構建識別此模式的檢測器是相對簡單的一件事件。(FindBugs 在核心檢測器集中有這樣一個檢測器。) 此技術不僅可以應用于 BigDecimal
,還可以應用于其他不可變類(如 BigInteger
、String
或 Color
)中。
花費一點時間為 bug 模式創建一個 bug 檢測器,它會為您帶來可觀的收益。不僅可以用比手工操作更少的工作和更高的信心來審核整個項目,從中尋找 bug,而且還可以在現在和將來將同一檢測器應用到其他項目中。您已針對不斷恢復、隨時可能出現的 bug 類型建立了防御機制,而不是在逐個實例的基礎上解決 bug。
![]() ![]() |
![]()
|
示例 bug 檢測器
為說明編寫 FindBugs 檢測器的過程,我們編寫了一個簡單的檢測器,它可以查找對 System.gc()
的調用。(下載此示例檢測器代碼的 源代碼。) 雖然調用的 System.gc()
不一定是 bug,但在實踐中,它會帶來更多的問題(多于它解決的問題 )。尤其是,如果錯誤地調用了庫中隱藏的 System.gc()
,則會降低使用該庫的應用程序的性能,開發人員可能會感到很茫然,對性能會如此低下感動很奇怪。
編寫 bug 檢測器的第一步是識別被檢測的 bug 模式。在本例中,該模式非常簡單,只需調用 System.gc()
即可。要編寫識別字節碼中此模式的檢測器,則需要知道對應于 bug 模式的字節碼是什么。了解此問題的最好方法是編寫一個包含 bug 的小程序,對它進行編譯,并使用 javap -c
解開 .class
文件。清單 2 顯示了一個展示該 bug 的類:
清單 2. 展示 bug 模式(我們想為它構建一個檢測器)的代碼
|
清單 3 顯示了運行示例類時 javap -c
的輸出:
清單 3. 清單 2 中代碼的字節碼清單
|
我們很快知道靜態方法是通過 invokestatic
JVM 指令調用的,invokestatic
的操作數是 java/lang/system
類的 gc:()V
方法。字節碼中的方法簽名和類型名稱與源代碼中的略有不同,但它很容易用于字節碼使用的編碼。
使用 bug 模式示例編寫 FindBugs 檢測器非常簡單。清單 4 顯示了擴展 BytecodeScanningDetector
基礎類并重寫 sawOpcode()
方法的檢測器。當它遇到 invokestatic
指令時,它會檢查被調用方法的類和名稱,如果是 System.gc()
指令,它會報告 bug 實例。
清單 4. 查找調用 System.gc() 的 Bug 檢測器
|
將檢測器包裝為插件
創建新的 bug 檢測所需的最后一步是將其打包為一個插件。FindBugs 插件包含一個或多個 bug 檢測器、一個部署描述符和一個資源文件,它們被打包成一個 JAR 文件,放在 FindBugs 安裝的插件目錄中。稱為 findbugs.xml
的部署描述符將定義已知的 bug 檢測器和它報告的錯誤。稱為 messages.xml
(對于本地化版本稱為 messages_xx.xml
)的資源文件定義特定于語言的、將由 FindBugs GUI 使用的字符串,用它描述所報告的 bug。清單 5 和清單 6 顯示了示例 bug 檢測器的部署描述符和資源文件。插件 JAR 中可以包括多個資源文件的本地版本;部署描述符和資源文件放置在插件 JAR 的頂級目錄中。
清單 5. 示例 bug 檢測器的部署描述符
|
清單 6. 示例 bug 檢測器的資源文件
|
根據 JDK 1.4.2 類庫構建和包裝插件,并運行它,這會為我們帶來意想不到的效果:com.sun.imageio
中的幾個類(包括 JPEGImageReader
和 JPEGImageWriter
)將調用 System.gc()
!此結果還有另一個好處,即靜態分析的靈活性:創建 bug 檢測器后,它可以在任何地方查找 bug。
![]() ![]() |
![]()
|
結束語
靜態分析和自定義 bug 檢測器是提高軟件質量的非常有效的方法。通過為已知 bug 模式創建檢測器,我們不僅可以在特定項目的當前代碼基址中搜索 bug 模式,還可以在當前或以后的任何項目中搜索 bug 模式。創建 bug 檢測器所付出的額外努力將來會為您帶來質量方面的豐厚回報。
![]() ![]() |
![]()
|
下載
描述 | 名字 | 大小 | 下載方法 |
---|---|---|---|
Source code | j-jtp06206fb_plugin_src.jar | 8KB | HTTP |
文章來源于領測軟件測試網 http://www.kjueaiud.com/
版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
技術支持和業務聯系:info@testage.com.cn 電話:010-51297073
老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月