天天看點

android項目的JaCoCo代碼覆寫率入門使用一、項目使用覆寫率初衷二、覆寫率概念三、JaCoCo四、工程實作覆寫率五、報告分析

一、項目使用覆寫率初衷

    由于公司開發項目業務類型是給企業做定制項目,開發周期短。開發人員在開發過程中往往在将項目送出給測試組測試時,沒有進行全面項目測試,導緻後面測試組測試出來一堆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下

android項目的JaCoCo代碼覆寫率入門使用一、項目使用覆寫率初衷二、覆寫率概念三、JaCoCo四、工程實作覆寫率五、報告分析

5.生成報表的gradle指令

gradlew jacocoTestReport
           

還記得在gradle建立的task任務叫jacocoTestReport,就是将coverage.ec生成報表檔案可視化。

五、報告分析

報表在build/reports/jacoco/jacocoTestReport/html下,右擊查找index.html點選打開。

android項目的JaCoCo代碼覆寫率入門使用一、項目使用覆寫率初衷二、覆寫率概念三、JaCoCo四、工程實作覆寫率五、報告分析
android項目的JaCoCo代碼覆寫率入門使用一、項目使用覆寫率初衷二、覆寫率概念三、JaCoCo四、工程實作覆寫率五、報告分析
android項目的JaCoCo代碼覆寫率入門使用一、項目使用覆寫率初衷二、覆寫率概念三、JaCoCo四、工程實作覆寫率五、報告分析

如上圖所示,标記綠色的為分支覆寫充分,标記黃色的為部分分支覆寫(上圖沒有),标紅色的為未執行該分支;

Demo的下載下傳

小紅的測試生涯                                                        http://www.dzwanli.com.cn/?p=1374

使用 Jacoco 實作 Android 端手工測試覆寫率統計      https://testerhome.com/topics/8554