jacoco入门_Android jacoco 代码覆盖率测试入门
前言
最近同事搞了一個基于 jacoco 統(tǒng)計 Android 代碼覆蓋率測試的功能,可以統(tǒng)計每天手工測試的代碼覆蓋率.抱著好奇的心態(tài),自己也學(xué)習(xí)一下 jacoco,陸陸續(xù)續(xù)搞了三天終于有點結(jié)果了.
本文介紹僅僅在源碼中加入少量代碼就可以完成代碼覆蓋率覆測試.
代碼配置
build.gradle
在 app 目錄下的 build.gradle 配置 jacoco
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.7.9"
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.1'
compile 'org.jacoco:org.jacoco.core:0.7.9'
compile 'com.android.support.constraint:constraint-layout:+'
}
def coverageSourceDirs = [
'../app/src/main/java'
]
task jacocoTestReport(type: JacocoReport) {
group = "Reporting"
description = "Generate Jacoco coverage reports after running tests."
reports {
xml.enabled = true
html.enabled = true
}
classDirectories = fileTree(
dir: './build/intermediates/classes/debug',
excludes: ['**/R*.class',
'**/*$InjectAdapter.class',
'**/*$ModuleAdapter.class',
'**/*$ViewInjector*.class'
])
sourceDirectories = files(coverageSourceDirs)
executionData = files("$buildDir/outputs/code-coverage/connected/coverage.ec")
doFirst {
new File("$buildDir/intermediates/classes/").eachFileRecurse { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}
寫入 ec 文件
自定義一個 JacocoUtils 類,可以根據(jù)反射拿到方法、類的執(zhí)行代碼,寫入到.ec 文件
public static void generateEcFile(boolean isNew) {
// String DEFAULT_COVERAGE_FILE_PATH = NLog.getContext().getFilesDir().getPath().toString() + "/coverage.ec";
Log.d(TAG, "生成覆蓋率文件: " + DEFAULT_COVERAGE_FILE_PATH);
OutputStream out = null;
File mCoverageFilePath = new File(DEFAULT_COVERAGE_FILE_PATH);
try {
if (isNew && mCoverageFilePath.exists()) {
Log.d(TAG, "JacocoUtils_generateEcFile: 清除舊的ec文件");
mCoverageFilePath.delete();
}
if (!mCoverageFilePath.exists()) {
mCoverageFilePath.createNewFile();
}
out = new FileOutputStream(mCoverageFilePath.getPath(), true);
Object agent = Class.forName("org.jacoco.agent.rt.RT")
.getMethod("getAgent")
.invoke(null);
out.write((byte[]) agent.getClass().getMethod("getExecutionData", boolean.class)
.invoke(agent, false));
Log.d(TAG,"寫入" + DEFAULT_COVERAGE_FILE_PATH + "完成!" );
} catch (Exception e) {
Log.e(TAG, "generateEcFile: " + e.getMessage());
Log.e(TAG,e.toString());
} finally {
if (out == null)
return;
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用 Application 生成 ec
繼承 Application 類,重寫 onTrimMemory 方法,系統(tǒng)會根據(jù)不同的內(nèi)存狀態(tài)來回調(diào)
系統(tǒng)提供的回調(diào)有:
Application.onTrimMemory()
Activity.onTrimMemory()
Fragement.OnTrimMemory()
Service.onTrimMemory()
ContentProvider.OnTrimMemory()
OnTrimMemory的參數(shù)是一個int數(shù)值,代表不同的內(nèi)存狀態(tài):
TRIM_MEMORY_COMPLETE:內(nèi)存不足,并且該進(jìn)程在后臺進(jìn)程列表最后一個,馬上就要被清理
TRIM_MEMORY_MODERATE:內(nèi)存不足,并且該進(jìn)程在后臺進(jìn)程列表的中部。
TRIM_MEMORY_BACKGROUND:內(nèi)存不足,并且該進(jìn)程是后臺進(jìn)程。
TRIM_MEMORY_UI_HIDDEN:內(nèi)存不足,并且該進(jìn)程的UI已經(jīng)不可見了。
可以根據(jù) level == TRIM_MEMORY_UI_HIDDEN 來確定 app 已經(jīng)至于后臺,此時調(diào)用 generateEcFile 方法.
//判斷是否是后臺
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level == TRIM_MEMORY_UI_HIDDEN) {
isBackground = true;
notifyBackground();
}
}
private void notifyBackground() {
// This is where you can notify listeners, handle session tracking, etc
Log.d(TAG, "切到后臺");
JacocoUtils.generateEcFile(true);
}
操作步驟
給予 app 讀寫 sdcard 權(quán)限
因為我的是簡單的 demo 代碼,啟動沒有彈窗詢問讀寫 sdcard 權(quán)限,
Android6.0 以后是動態(tài)獲取權(quán)限了,所以需要手動去設(shè)置中把 sdcard 權(quán)限打開,實際項目應(yīng)該不存在手動打開的步驟.
手工執(zhí)行
安裝 app->操作 app->app 至于后臺->分析 ec 文件.
自動化執(zhí)行
可以結(jié)合 monkey 和 UI 自動化,我簡單寫了個 shell 腳本.從編譯 app、啟動 app、app 至于后臺、自動展示 jacoco 報告
#!/usr/bin/env bash
#當(dāng)前在環(huán)境為Project/app目錄
apk_path=`pwd`/app/build/outputs/apk/app-debug.apk
report_path=`pwd`/reporter/index.html
echo "打包app"
gradle assembleDebug
adb uninstall com.weex.jasso
echo "安裝app"
adb install ${apk_path}
echo "啟動app"
adb shell am start -W -n com.weex.jasso/.Test1Activity -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000
sleep2
echo "關(guān)閉app"
adb shell am force-stop com.weex.jasso
rm -rf `pwd`/new.ec
rm -rf `pwd`/report
adb pull /sdcard/jacoco/coverage.ec `pwd`/new.ec
macaca coverage -r java -f `pwd`/new.ec -c `pwd`/app/build/intermediates/classes/debug -s `pwd`/app/src/main/java --html `pwd`/reporter
echo "jacoco報告地址:"${report_path}
open -a "/Applications/Safari.app" ${report_path}
效果
macaca coverage 生產(chǎn)報告
使用 gradle 的 jacocoTestReport 也可以生產(chǎn)報告,也是大多人使用的方式,本文就不做介紹了,主要介紹使用 macaca coverage 方法.
macaca coverage 可以生成 jacoco 報告,不僅可以生成 Android 項目,也可以生產(chǎn) iOS、web 項目.具體使用請查看https://macacajs.github.io/zh/coverage.
安裝macaca-coverage命令:
npm i macaca-cli -g
macaca coverage -h
npm i macaca-coverage --save-dev macaca coverage命令:
macaca coverage -r java -f `pwd`/new.ec -c `pwd`/app/build/intermediates/classes/debug -s `pwd`/app/src/main/java --html `pwd`/reporter
項目代碼 https://github.com/xinxi1990/jacocodemo.git
在項目根目錄有個jacaco_test.sh,可以完成自動化測試.
學(xué)習(xí)帖
總結(jié)
以上是生活随笔為你收集整理的jacoco入门_Android jacoco 代码覆盖率测试入门的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 让8只数码管初始显示零,每隔大约1s加一
- 下一篇: c java开发对比_编程语言:Java