簡介如何利用JaCoCo取得Android專案的覆蓋率報告
簡介如何利用JaCoCo取得Android專案的覆蓋率報告
作者:YiKai Chuang
前言:
JaCoCo是Java Code Coverage的縮寫,它可以跟Ant、Maven或Jenkins整合,快速找出專案的原始程式碼有哪些地方沒有被Unit Test(單元測試)所覆蓋,本文是基於Android專案的androidTest資料夾裡頭已經有寫好Espresso的單元測試程式碼的前提下,對於如何套用JaCoCo,讓Android專案執行完Espresso測試的同時,可以產出test coverage report(覆蓋率報告),做一個概括性的介紹。
在Android專案串接JaCoCo:
-
首先,需要修改app層級的build.gradle:加上apply plugin: 'jacoco'這行,因為Android Plugin for Gradle從0.10.0版開始支援了JaCoCo,所以只要在build.gradle的buildTypes裡宣告testCoverageEnabled = true這行,就可以利用JaCoCo外掛,做簡單的覆蓋率測試。另外,因為在build.gradle的buildTypes的debug內宣告testCoverageEnabled = true,所以之後會有createDebugCoverageReport的task可以用
-
有些文章提到產出覆蓋率報告時需要在AndroidManifest.xml加上允許檔案讀寫的權限(譬如:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />),測試之後發現即使不加,應該也不會有什麼影響
-
點擊Android Studio的Gradle,找到專案名稱底下的Tasks的verification資料夾,連續點擊connectedAndroidTest(或connectedCheck或connectedAndroidDebugTest或createDebugCoverageReport)兩次之後,便會開始在手機上執行Espresso的單元測試
-
以連續點擊createDebugCoverageReport兩次為例,當手機執行完Espresso的單元測試之後,Android Studio會出現BUILD SUCCESSFUL和Task execution finished 'createDebugCoverageReport'的提示訊息
-
以我個人的習慣,會先確認執行Espresso測試是否完全沒問題,所以通常都先看build資料夾的reports資料夾的androidTests資料夾的報告
-
若測試過程一切正常,點擊index.html之後,會看到類似這樣的產出報告
-
接著開啟build資料夾的reports資料夾的coverage資料夾,就可以看到JaCoCo產出的覆蓋率報告
JaCoCo覆蓋率報告的簡介:
-
JaCoCo包含了各種覆蓋率的計數器,譬如:Instructions coverage(執行的最小單位)、Branches coverage(值得注意的一點是:異常處理不列入計算)、Cyclomatic Complexity(簡單來說就是為了覆蓋所有路徑所需執行的單元測試的數量,若數值越大,表示原始程式碼可能越難測試和維護)、Lines(計算被測試程式的每行程式碼是否被執行)、Non-abstract methods(計算被測試程式的非抽象方法是否被執行)、Classes(計算被測試程式的class類檔案是否被執行)
-
橫條的紅色部份表示單元測試尚未覆蓋的比重,橫條的綠色部分表示單元測試已經覆蓋的比重,若橫條的長度越長,表示該Element在整份報告中所佔的權重越高
-
以最底下Total旁邊的數值為例,984是目前尚未覆蓋的指令數,1632是全部的指令數,因此覆蓋率(coverage) = (1632-984) / 1632 = 39.7%
實作後的心得分享:
因為做某客戶的案子才第一次接觸JaCoCo,過程當中的感想、心得是
-
專案的原始程式碼寫得越模組化,在做單元測試時就會越輕鬆
-
也許是經驗不足,這次在產出JaCoCo報告時遇到的最大困難,就是原本想過濾掉跟Data Binding有關的程式碼,讓它不要出現在JaCoCo覆蓋率報告裡面。雖然參考過很多篇文章,也在build.gradle將Data Binding相關的packag name、檔名...等加到排除的條件,但就是一直無法出現預期的結果
(圖片引用自https://github.com/nongdenchet/android-data-binding/blob/master/jacoco.gradle)
-
若想提升JaCoCo報告的整體覆蓋率,建議找權重比較高的優先處理,所謂「擒賊先擒王」,同樣也適用於單元測試
最後總結:
這次參與的專案是等到Android主要程式都完成之後,才開始補做單元測試。然而,透過這次的經驗,也親身體驗到,若能在專案一開始,邊寫程式的同時,就邊寫各種不同邊界條件(boundary case)的單元測試程式碼,測試Android程式各個function的邏輯是否正確?是否有潛藏的漏洞(譬如:計算數值時除數在某些情況下有可能為0)?...等,諸如此類的單元測試的case越多,相信越有助於讓原始程式碼變得更為強健(robust),進而提升整個專案的軟體品質
參考來源: