一、項目使用覆寫率初衷
由于公司開發項目業務類型是給企業做定制項目,開發周期短。開發人員在開發過程中往往在将項目送出給測試組測試時,沒有進行全面項目測試,導緻後面測試組測試出來一堆bug問題,甚至中斷測試流程。為了解決大量開發和測試人員的時間,以及檢測項目測試的代碼是否測試覆寫的程度。在這種條件下,決定使用代碼覆寫率來進行檢視控制。
二、覆寫率概念
代碼覆寫率分析實際上一種度量方式,間接度量品質的方法的過程,是在保證測試品質的時候潛在保證明際産品的品質,在程式中尋找沒有被測試用例測試過的地方的流程,建立新的測試用例來增加覆寫率的流程。
代碼覆寫分析是一種結構測試技術,屬于白盒測試的範疇,結構化測試是以源代碼的意圖表現為依據來比較被測試程式行為的,與以需求規格為依據去比較被測程式行為的功能測試形成對比,結構化測試檢查程式是如何工作的,以及代碼結構和邏輯方面的潛在缺陷,而功能測試是不管程式内部是如何運作的,它隻檢查以及關心程式實作了什麼。另外代碼覆寫有時被稱為“覆寫分析”、“測試覆寫分析”、“測試覆寫”、“覆寫螢幕”等。
三、JaCoCo
JaCoCo簡述
JaCoCo是一個開源的覆寫率工具(官網位址: http://www.eclemma.org/JaCoCo/ ),它針對的開發語言是java,其使用方法很靈活,可以嵌入到Ant、Maven中;可以作為Eclipse插件,可以使用其JavaAgent技術監控Java程式等等。很多第三方的工具提供了對JaCoCo的內建,如sonar、Jenkins等。
JaCoCo包含了多種尺度的覆寫率計數器,包含指令級覆寫(Instructions,C0coverage),分支(Branches,C1coverage)、圈複雜度(CyclomaticComplexity)、行覆寫(Lines)、方法覆寫(non-abstract methods)、類覆寫(classes),這裡就詳細介紹不屬于入門使用範疇。
四、工程實作覆寫率
在app目錄的gradle檔案
apply plugin: 'com.android.application'
apply plugin: 'jacoco'//添加插件jacoco
jacoco {
toolVersion = "0.7.9"//聲明jacoco的版本号
}
android {
compileSdkVersion
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.weex.jasso"
minSdkVersion
targetSdkVersion
versionCode
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
testCoverageEnabled = true//設定為true
}
}
}
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'//導入jacoco的版本包
compile 'com.android.support.constraint:constraint-layout:+'
}
def coverageSourceDirs = [
'../app/src/main/java'
]
//建立task任務将outputs/code-coverage/connected/目錄下coverage.ec檔案的生成覆寫率報告
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('$$', '$'))
}
}
}
}
生成代碼覆寫率的檔案
1. 建立基礎類BaseActivity
public abstract class BaseActivity extends Activity {
public static String DEFAULT_COVERAGE_FILE_PATH = Environment.getExternalStorageDirectory()+"/hb/oe/";
public static String TAG=Test1Activity.class.getName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createFile(DEFAULT_COVERAGE_FILE_PATH,"coverage.ec");
}
@Override
protected void onDestroy() {
super.onDestroy();
closeFile();
}
public static void createFile(String path,String fileName){
File file =null;
if (path==null){
new Exception("path no null");
}
if (fileName==null){
file = new File(path);
}else {
file=new File(path,fileName);
}
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
public void closeFile(){
OutputStream out = null;
try {
out = new FileOutputStream(DEFAULT_COVERAGE_FILE_PATH+"/coverage.ec", false);
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));
} catch (Exception e) {
Log.d(TAG, e.toString(), e);
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
基礎類在oncreate()建立coverage.ec檔案用于寫入代碼覆寫率及方法createFile()方法,在界面關閉的onDestroy()生命周期寫入覆寫資料方法closeFile();
2. 其他界面的activity繼承基礎類BaseActivity
這裡我為了示範寫了Demo,寫了兩個類Test1Activity 和test2Activity
Test1Activity .class
public class Test1Activity extends BaseActivity {
private Button mToastBtn;
private Button mRequireBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void require(){
Toast.makeText(this,"網絡請求",Toast.LENGTH_LONG).show();
}
public void toast(){
Intent intent=new Intent(this,Test2Activity.class);
startActivity(intent);
}
public void showTips(View view){
Toast.makeText(this, "我是提示資訊", Toast.LENGTH_SHORT).show();
}
public void showError(View view){
Toast.makeText(this,"我正在抛出錯誤",Toast.LENGTH_SHORT).show();
startActivity(new Intent(this,Test2Activity.class));
finish();
}
public void showTest(){
Toast.makeText(this,"測試",Toast.LENGTH_SHORT).show();
}
}
Test2Activity.class
public class Test2Activity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
}
在Test1Activity寫了兩個按鈕點選事件,用于明确差別事件點選覆寫率;
3. 直接app運作到手機端
4. 生成報告
将手機中的coverage.ec檔案(上述代碼有具體路徑,可以自行日記列印出來,沿着相對路徑去找)複制到build/outputs/code-coverage/connected下
5.生成報表的gradle指令
gradlew jacocoTestReport
還記得在gradle建立的task任務叫jacocoTestReport,就是将coverage.ec生成報表檔案可視化。
五、報告分析
報表在build/reports/jacoco/jacocoTestReport/html下,右擊查找index.html點選打開。
如上圖所示,标記綠色的為分支覆寫充分,标記黃色的為部分分支覆寫(上圖沒有),标紅色的為未執行該分支;
Demo的下載下傳
小紅的測試生涯 http://www.dzwanli.com.cn/?p=1374
使用 Jacoco 實作 Android 端手工測試覆寫率統計 https://testerhome.com/topics/8554