android项目的JaCoCo代码覆盖率入门使用

来源:互联网 发布:c语言调用lib 编辑:程序博客网 时间:2024/05/21 23:46

一、项目使用覆盖率初衷

    由于公司开发项目业务类型是给企业做定制项目,开发周期短。开发人员在开发过程中往往在将项目提交给测试组测试时,没有进行全面项目测试,导致后面测试组测试出来一堆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'//添加插件jacocojacoco {    toolVersion = "0.7.9"//声明jacoco的版本号}android {    compileSdkVersion 25    buildToolsVersion "25.0.2"    defaultConfig {        applicationId "com.weex.jasso"        minSdkVersion 16        targetSdkVersion 25        versionCode 1        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

阅读全文
0 0
原创粉丝点击