zoukankan      html  css  js  c++  java
  • 安卓-Jacoco-精准测试应用

    Jacoco-精准测试

    开源地址:https://github.com/seasonxie/JacocoAndroid

    不依赖源码执行
    接口测试也能直观看出覆盖度
    知道什么样的用例保证哪块的代码,更好的精准度测试

     

     1.实现jacoco Instrumentation操作(后面通过命令直接启动该instrument,最下面有),注意最后启动了 InstrumentedActivity

    public class JacocoInstrumentation extends Instrumentation
    
     @Override
        public void onCreate(Bundle arguments) {
            super.onCreate(arguments);
            DEFAULT_COVERAGE_FILE_PATH = "/sdcard/cover.ec";
    
            File file = new File(DEFAULT_COVERAGE_FILE_PATH);
            if (!file.exists()) {
                try {
                    file.createNewFile();
                } catch (IOException e) {
                    Log.d(TAG, "异常 : " + e);
                    e.printStackTrace();
                }
            }
            if (arguments != null) {
                //mCoverage = getBooleanArgument(arguments, "coverage");
                mCoverageFilePath = arguments.getString("coverageFile");
            }
    
            mIntent = new Intent(getTargetContext(), InstrumentedActivity.class);
            mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            start();
        }

     

    2.在InstrumentedActivity  onDestroy设置监听,当触发的时候触发生成jacoco覆盖率文件

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  权限
    InstrumentedActivity extends MainActivity {
        public static String TAG = "InstrumentedActivity";
    
        private FinishListener mListener;
    
        public void setFinishListener(FinishListener listener) {
            mListener = listener;
        }
    
    
        @Override
        public void onDestroy() {
            Log.d(TAG + ".InstrumentedActivity", "onDestroy()");
            super.finish();
            if (mListener != null) {
                mListener.onActivityFinished();
            }
        }
    
    }

    3.触发监听的操作

    private void generateCoverageReport() {
            Log.d(TAG, "generateCoverageReport():" + getCoverageFilePath());
            OutputStream out = null;
            try {
                out = new FileOutputStream(getCoverageFilePath(), 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();
                    }
                }
            }
        }

     

    启动:

    2.1注册instrumentation,通过instrumentation启动被测应用

    adb shell am instrument com.jacs.zhaotang.jscscs/test.JacocoInstrumentation

        <instrumentation
            android:handleProfiling="true"
            android:label="CoverageInstrumentation"
            android:name="test.JacocoInstrumentation"
            android:targetPackage="com.jacs.zhaotang.jscscs"/>

     

    3.把生成的jacoco覆盖率文件放在指定文件夹,用gradle生成htmlreport

     将该文件拖至入app根目录/build/outputs/code-coverage/connected下(文件夹没有的话可新建)

     运行gradlew jacocoTestReport

    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('$$', '$'))
                }
            }
        }
    }

     

    4.report路径:jscscsappuild eportsjacocojacocoTestReport

     

    通过广播驱动生成ec:

    1.注册广播

     public void onReceive(Context context, Intent intent) {
            String url = intent.getStringExtra("url");
            if (Constants.mListener != null) {
                Constants.mListener.onActivityFinished();
                Toast.makeText(context,"notnull", 0).show();
            }else{
                Toast.makeText(context,url, 0).show();
            }
    }
     <receiver android:name="test.operationReceiver" android:enabled="true" android:exported="true">
                <intent-filter>
                    <action android:name="com.jacs.zhaotang.jscscs.operationReceiver" />
                </intent-filter>
            </receiver>

    发送广播:adb shell am broadcast -a com.jacs.zhaotang.jscscs.operationReceiver --es url 'sdsd'

     

     

    解析xml:

    需要提取的覆盖率类型

        public static final String INSTRUCTION="INSTRUCTION";
        public static final String BRANCH="BRANCH";
        public static final String LINE="LINE";
        public static final String COMPLEXITY="COMPLEXITY";
        public static final String METHOD="METHOD";
        public static final String[] COVERES={INSTRUCTION};

     

    // 获取当前节点的所有属性节点
            List<Attribute> list = node.attributes();
            // 遍历属性节点
            for (Attribute attr : list) {
                if (node.getName().equals("counter")) { // 节点等于 counter
                    if (needCollect(attr.getText()) || is) { // 当属性等于INSTRUCTION拿出covered                                        // INSTRUCTION                                                                    // 拿出该covered
                        is = true;
                    }
                    if (attr.getName().equals("covered") && is) {
                        String p=getFristAttributeText(node.getParent());
                        data += node.getParent().getName() + " -  "
                                + p + " ---  "
                                + currentCovered+"-"+attr.getName() + " ----- " + attr.getText()
                                + "  ";
                        is = false;
                        break;
                    }
    
                }
    
            }

     

    获取A和B两次代码的覆盖率

    method -  unRegisterObserver ---  INSTRUCTION-covered ----- 14  
    method -  getLastLocation ---  INSTRUCTION-covered ----- 18  
    method -  setCachedLocation ---  INSTRUCTION-covered ----- 0  
    method -  getCachedLocation ---  INSTRUCTION-covered ----- 11  
    method -  setCachedLocationTime ---  INSTRUCTION-covered ----- 0  
    method -  getCacheLocationTime ---  INSTRUCTION-covered ----- 11  
    method -  hasCachedLocation ---  INSTRUCTION-covered ----- 10  
    method -  <init> ---  INSTRUCTION-covered ----- 6  
    method -  onReceive ---  INSTRUCTION-covered ----- 10  
    Spent  785  //消耗时间

    打印A/B两次的不同覆盖值
    A: class - com/android/browser/AutoLoginLinearLayout --- INSTRUCTION-covered ----- 20 B: class - com/android/browser/AutoLoginLinearLayout --- INSTRUCTION-covered ----- 0

     

  • 相关阅读:
    MVC已经是现代Web开发中的一个很重要的部分,下面介绍一下Spring MVC的一些使用心得。
    @MySQL的存储引擎
    SpringMVC关于json、xml自动转换的原理研究
    json-lib 的maven dependency
    58到家数据库30条军规解读
    @Linux下Redis的安装
    Redis的5个常见使用场景
    Json对象和Json字符串的区别
    @查看MySQL版本的方法
    @java.lang.NoSuchMethodError
  • 原文地址:https://www.cnblogs.com/season-xie/p/6337906.html
Copyright © 2011-2022 走看看