【騰訊TMQ】JAVA程式碼覆蓋率工具JaCoCo-踩坑篇
作者:劉洋
一、覆蓋率踩過的坑
在專案中使用JaCoCo覆蓋率的時候,也遇到過各種奇葩的問題,在這裡列出來分享下,問題和實際的專案關係密切,希望對有遇到過相似問題的童鞋有所啟發。
1.1 覆蓋率包在部分手機6.0上安裝失敗
事情起因:在測試新功能時,用打的覆蓋率包,外包反饋部分手機6.0上安裝不了。
問題重現:試了在自己的手機,華為mate8的6.0系統上安裝正常,屬於部分機型問題。
將問題小米手機借來後,發現用豌豆莢或者應用寶確實安裝失敗,提示“該應用簽名有問題,無法安裝。”通過adb install安裝,提示INSTALL_PARSE_FAILED_NO_CERTIFICATES
懷疑是部分廠商對簽名的校驗級別比較高。
問題排解:網上有種說法,jdk1.7以後變更了預設的加密演算法,而簽名程式沒有,所以需要在簽名時用引數指定。具體方法:在簽名命令後加入-digestalg SHA1 -sigalg MD5withRSA
1.會不會這種情況導致:查了應用寶的打包指令碼,簽名部分已經增加。
此種情況排除
2、會不會簽名檔案有問題?
重新排查了打包過程的簽名,金鑰和口令都和RDM打包一樣,對ANDROIDR.RSA、ANDROIDR.SF、MANIFEST.MF,清除掉簽名,重新進行簽名,問題仍然存在。
此種情況排除
3、JaCoCo的jar包重新簽名
和RDM打包,也就增加了JaCoCo部分,會不會是JaCoCo的兩個jar包jacocoagent.jar和jacocoagent.jar出的問題?
這兩個jar包已經是簽名過的,會不會需要用應用寶的簽名進行重新籤?
使用jarsigner重新對這兩個jar包用應用寶的金鑰進行簽名,打包安裝,問題仍然存在。
此種情況排除
到這裡,網上的各種方法基本都試過了,沒任何效果,問題糾結在這裡了。
靜下心來,網上的方法沒任何效果,還是回到專案中,重新一步一步的對比RDM打包和覆蓋率打包的區別,逐步排查吧。
4、RDM打包和覆蓋率打包逐一對比
….(這裡省略一萬字,都是排查)
簽名部分的日誌對比:
我們還是回到打包簽名的target:sign_obfuscated
逐行對比RDM和我們覆蓋率打包的日誌:
發現了一個不同的點:
RDM的:
我們打包的:
大家看出差別了沒(紅色部分)
紅色部分為jacocoagent.jar包裡的非class檔案,signer對這兩個檔案也進行了簽名。
到這裡都不是問題。
問題還是應用寶指令碼本身(┬_┬哭~)
簽名後做compress和zipalign,據說是極限壓縮,減少包的大小。
Compress會呼叫compress_yingyongbao.sh指令碼,這裡列出了所有要壓縮的檔案
看到沒,看到沒,它重新按這裡的檔案列表壓縮打包,丟掉了上面JaCoCo裡面的兩個檔案應用在打包後,簽名檔案是存在JaCoCo這兩個檔案的,但打包後找不到這兩個檔案,因此安裝時有的手機提示簽名有問題。
解決方法:
JaCoCo這兩個檔案,一個是屬性檔案,一個是生成xml的dtd檔案,對我們生成覆蓋率沒多大作用,我們把這兩個從jar包裡刪除,在重新打包,這兩個檔案不存在了,也就不用簽名了,問題就解決了。
1.2 覆蓋率包在部分4.X版本手機上生成ec檔案失敗
事情起因:在測試新功能時,用打的覆蓋率包,外包反饋部分4.X手機生成不了ec檔案
問題重現:試了在自己的手機,華為mate8的6.0系統上生成正常,屬於部分機型問題。
將問題手機借來後,生成ec檔案提示失敗。
問題排解:
檢視logcat日誌:
java.lang.IllegalAccessError:
07-02 16:21:19.768: W/dalvikvm(557): Class resolved by unexpected DEX: Lorg.JaCoCo.agent.rt.internal.Agent(0x44f0d158):0x128f18 ref [Lorg.JaCoCo.agent.rt.internal.Agent;] Lorg.JaCoCo.agent.rt.internal.Agent;(0x44f0d158):0x11df68
還有一段:
反射RT類的getAgent() 方法是提示
`java.lang.reflect.InvocationTargetException`
(1)反射在其他手機是正常的,按道理不應該在部分問題手機會失敗,但也做一下排查報錯的程式碼行:
網上有說InvocationTargetException問題可能是沒有設定可見就訪問私有先看看RT的這個方法
在看看Agent類的這個方法:
嘗試把私有欄位可見,在去呼叫
結果問題仍然存在,此種情況排除
(2)那我們就回到第一個錯誤, Class resolved by unexpected DEX
Agent出了兩個地址。
我們在回過頭來看應用寶的打包指令碼,看看dex幹了什麼。
呼叫dex,輸入classes,輸出dex,下面對excludes裡面的jar進行了排除
呼叫dex_sub,輸入subclasses,輸出second_dex,下面對excludes裡面的jar進行了排除
回過頭來在看看我們的插樁指令碼,對dex、dex_sub這塊只改了classes為classes_instr(用插樁後的打dex)
應用寶這個分包的邏輯,會分別打兩個dex。
問題就找到了,因為沒有改excludes部分,jacocoagent.jar是放在應用寶libs目錄下的,預設dex和dex_sub都把jacocoagent.jar打了進去,執行時就會出現新的dex想要替換之前校驗過的dex,也就出現agent有兩個地址的緣故。
解決方法:
覆蓋率打包的指令碼,對dex_sub的excludes中加入jacocoagent.jar,這樣兩次dex只打一次jacocoagent.jar。
重新打包,ec檔案正常生成。
1.3 覆蓋率報告生成後看不到原始碼覆蓋情況
原始碼和類檔案都正確指定了,為什麼生成的報告看不到原始碼覆蓋?
**
解決方法:**
(1)編譯的時候debug=”true” 這個一定要設定,比如
(2)如果1沒有錯誤,那就要看看你的原始碼和class檔案路徑指定正確沒,JaCoCo是按照包名去搜索的,這個一定要確定好,很多專案會自建程式碼目錄的。
二、覆蓋率一些需要注意的地方
由於Android不能通過JVM停止後自動dump覆蓋率資料,因此當Android應用程序不存在或停止的時候,覆蓋率資料不會生成。
也就有了如下需要注意的地方
(1) 沒有啟動應用程序,生成覆蓋率資料會失敗。
(2) 覆蓋率生成工具程序殺不殺掉,不影響覆蓋率生成結果。
(3) 測試過程中,殺掉應用程序,記憶體中的覆蓋率資料會丟失。
(4) 覆蓋率資料是可以追加記錄的,但最好在殺掉應用程序前先備份。
建議養成良好的操作習慣,,定期生成覆蓋率檔案。
如果有殺掉應用程序的需求操作,請在操作前生成一次,這樣之前的資料就有所保留了。
一次測試前,一定要保證先清理掉以前覆蓋率的資料,否則以現有追加檔案的方式的形式,會導致舊新的覆蓋率柔和在一起,有可能merge時候會失敗。
本章完~
我們專注於移動測試技術精華,飽含騰訊多款億級APP的品質祕密,文章皆獨家原創,我們不談虛的,只談乾貨!
掃碼關注我們