引言
經常有人問這樣的問題:“我們在做單元測試,那測試覆蓋率要到多少才行?”。答案其實很簡答,“作為指標的測試覆蓋率都是沒有用處的。”
Martin Fowler(重構那本書的作者)曾經寫過一篇博客來討論這個問題,他指出:把測試覆蓋作為質量目標沒有任何意義,而我們應該把它作為一種發現未被測試覆蓋的代碼的手段。
代碼覆蓋率的意義
分析未覆蓋部分的代碼,從而反推在前期測試設計是否充分,沒有覆蓋到的代碼是否是測試設計的盲點,為什么沒有考慮到?需求/設計不夠清晰,測試設計的理解有誤,工程方法應用后的造成的策略性放棄等等,之后進行補充測試用例設計。
檢測出程序中的廢代碼,可以逆向反推在代碼設計中思維混亂點,提醒設計/開發人員理清代碼邏輯關系,提升代碼質量。
代碼覆蓋率高不能說明代碼質量高,但是反過來看,代碼覆蓋率低,代碼質量不會高到哪里去,可以作為測試自我審視的重要工具之一。
代碼覆蓋率工具
目前Java常用覆蓋率工具Jacoco、Emma和Cobertura
覆蓋率工具工作流程
1. 對Java字節碼進行插樁,On-The-Fly和Offine兩種方式。
2. 執行測試用例,收集程序執行軌跡信息,將其dump到內存。
3. 數據處理器結合程序執行軌跡信息和代碼結構信息分析生成代碼覆蓋率報告。
4. 將代碼覆蓋率報告圖形化展示出來,如html、xml等文件格式。
插樁原理
主流代碼覆蓋率工具都采用字節碼插樁模式,通過鉤子的方式來記錄代碼執行軌跡信息。其中字節碼插樁又分為兩種模式On-The-Fly和Offine。 On-The-Fly模式優點在于無需修改源代碼,可以在系統不停機的情況下,實時收集代碼覆蓋率信息。Offine模式優點在于系統啟動不需要額外開啟代理,但是只能在系統停機的情況下才能獲取代碼覆蓋率。 基于以上特性,同時由于公司使用JDK8,我們采用Jacoco來獲取集成測試代碼覆蓋率,單元測試使用Cobertura。
On-The-Fly插樁 Java Agent
JVM中通過-javaagent參數指定特定的jar文件啟動Instrumentation的代理程序
代理程序在每裝載一個class文件前判斷是否已經轉換修改了該文件,如果沒有則需要將探針插入class文件中。
代碼覆蓋率就可以在JVM執行代碼的時候實時獲取。
典型代表:Jacoco
On-The-Fly插樁 Class Loader
自定義classloader實現自己的類裝載策略,在類加載之前將探針插入class文件中
典型代表:Emma
Offine插樁
在測試之前先對文件進行插樁,生成插過樁的class文件或者jar包,執行插過樁的class文件或者jar包之后,會生成覆蓋率信息到文件,最后統一對覆蓋率信息進行處理,并生成報告。
Offline插樁又分為兩種:
Replace:修改字節碼生成新的class文件
Inject:在原有字節碼文件上進行修改
典型代表:Cobertura
On-The-Fly和Offine比較
On-The-Fly模式更加方便的獲取代碼覆蓋率,無需提前進行字節碼插樁,可以實時獲取代碼覆蓋率信息
Offline模式適用于以下場景:
運行環境不支持java agent
部署環境不允許設置JVM參數
字節碼需要被轉換成其他虛擬機字節碼,如Android Dalvik VM
動態修改字節碼過程中和其他agent沖突
無法自定義用戶加載類
實踐應用
單元測試覆蓋率
目前有贊開發人員會寫單元測試用例,為了能夠引入持續集成,我們選取了Sonar+Cobertura來獲取單元測試覆蓋率。 我們將代碼覆蓋率綁定到代碼編譯階段,這樣每次代碼編譯就能夠執行單元測試同時獲取代碼單元測試覆蓋率
org.codehaus.mojo
cobertura-maven-plugin
2.7
xml
原文轉自: http://tech.youzan.com/code-coverage/