Android-jacoco code coverage: functional testing unit test coverage coverage +

Reference: https: //docs.gradle.org/current/dsl/org.gradle.testing.jacoco.tasks.JacocoCoverageVerification.html

gradle Library Download: https: //maven.aliyun.com/mvn/view

Case Reference Source: https: //www.jianshu.com/p/1a4a81f09526

https://www.jianshu.com/p/1a4a81f09526

Other: https: //testerhome.com/topics/8329

 

These days toss for a long time, is now the main case are based gradle3.1.3 version, I do not want to use the old version, check some information he changed under the code, it can be used.

antecedent:

Before you can use Android heard jacoco + monkey do code coverage test, previously only had a spring unit test coverage jacoco the demo, thought Android features and jacoco can be united, very busy these days to engage in a bit.

Ready to work:

Have Android project source code, without modifying the core code of the main project, but need to write some code jacoco, mainly using instrument recording code coverage at the end of acitivity;

The specific content of two points:

A, Android project unit test code coverage:

Use AndroidStudio own task to view the current unit test coverage AndroidTest folder under the circumstances

Edit build.gradle

{Android 
    ... 
    defaultConfig { 
         ... 
        testInstrumentationRunnerArguments clearPackageData: 'to true' 
// perform cleanup test instrumentation cache 
    } 
    buildTypes { 
        Debug { 
            testCoverageEnabled to true = 
            / ** Open coverage statistics switch 
             * / 
        } 
    }

  

Installing debug packages

 

 

AndroidTest execution coverage tests and output reports

 

 

Execution log is this:

  Here is a fragment removal AndroidTest execution unit testing, by sending commands to the phone adb instrument, a test is performed, obtaining coverage data from the phone down and down:

Executing tasks: [createDebugAndroidTestCoverageReport]
...
> Task :app:connectedDebugAndroidTest
...
05:40:39 V/ddms: execute: running am instrument -w -r   -e coverageFile /data/data/com.patech.testApp/coverage.ec -e coverage true -e clearPackageData true com.patech.testApp.test/androidx.test.runner.AndroidJUnitRunner
...
05:40:41 V/InstrumentationResultParser: com.patech.testApp.EspressoTest:
...
05:40:58 V/InstrumentationResultParser: Time: 17.669
05:40:58 V/InstrumentationResultParser: 
05:40:58 V/InstrumentationResultParser: OK (5 tests)
05:40:58 V/InstrumentationResultParser: 
05:40:58 V/InstrumentationResultParser: 
05:40:58 V/InstrumentationResultParser: Generated code coverage data to /data/data/com.patech.testApp/coverage.ec
05:40:58 V/InstrumentationResultParser: INSTRUMENTATION_CODE: -1
...
05:40:59 I/XmlResultReporter: XML test result file generated at D:\androidStudio\MyApplication\app\build\outputs\androidTest-results\connected\TEST-VOG-AL10 - 9-app-.xml. Total tests 5, passed 5, 
05:40:59 V/ddms: execute 'am instrument -w -r   -e coverageFile /data/data/com.patech.testApp/coverage.ec -e coverage true -e clearPackageData true com.patech.testApp.test/androidx.test.runner.AndroidJUnitRunner' on 'APH0219430006864' : EOF hit. Read: -1
...
05:40:59 D/com.patech.testApp.coverage.ec: Downloading com.patech.testApp.coverage.ec from device 'APH0219430006864'
...

  

View reports in the build after finishing execution details

 

 

 

II. Jacoco + instrument to write code, after performing functional tests, ec file generated locally, spread to the pc-parsed into html format to view the implementation of the code coverage function test operation

1. Preparation of FinishListener Interface

public interface FinishListener {
    void onActivityFinished();
    void dumpIntermediateCoverage(String filePath);
}

  

Write jacocoInstrumentation methods to achieve above this interface, the online copy to achieve a generation after the implementation of complete coverage of file and save it locally to your phone:

package com.patech.test;

import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;

import com.patech.testApp.InstrumentedActivity;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;

public class JacocoInstrumentation extends Instrumentation implements FinishListener{

    public static String TAG = "JacocoInstrumentation:";
    private static String DEFAULT_COVERAGE_FILE_PATH = "/mnt/sdcard/coverage.ec";

    private final Bundle mResults = new Bundle();

    private Intent mIntent;
    //LOGD 调试用布尔
    private static final boolean LOGD = true;

    private boolean mCoverage = true;

    private String mCoverageFilePath;

    public JacocoInstrumentation(){

    }

    @Override
    public void onCreate(Bundle arguments) {
        Log.d(TAG, "onCreate(" + arguments + ")");
        super.onCreate(arguments);
        //DEFAULT_COVERAGE_FILE_PATH = getContext().getFilesDir().getPath() + "/coverage.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) {
            mCoverageFilePath = arguments.getString("coverageFile");
        }

        mIntent = new Intent(getTargetContext(), InstrumentedActivity.class);
        mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        start();
    }

    public void onStart() {
        if (LOGD)
            Log.d(TAG,"onStart()");
        super.onStart();

        Looper.prepare();
/*        InstrumentedActivity activity = (InstrumentedActivity) startActivitySync(mIntent);
        activity.setFinishListener(this);*/
    }

    private boolean getBooleanArgument(Bundle arguments, String tag) {
        String tagString = arguments.getString(tag);
        return tagString != null && Boolean.parseBoolean(tagString);
    }

    private String getCoverageFilePath() {
        if (mCoverageFilePath == null) {
            return DEFAULT_COVERAGE_FILE_PATH;
        }else {
            return mCoverageFilePath;
        }
    }

    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 (FileNotFoundException e) {
            Log.d(TAG, e.toString(), e);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void UsegenerateCoverageReport() {
        generateCoverageReport();
    }

    private boolean setCoverageFilePath(String filePath){
        if (filePath != null && filePath.length() > 0) {
            mCoverageFilePath = filePath;
        }
        return false;
    }

    private void reportEmmaError(Exception e) {
        reportEmmaError(e);
    }

    private void reportEmmaError(String hint, Exception e) {
        String msg = "Failed to generate emma coverage. " +hint;
        Log.e(TAG, msg, e);
        mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER,"\nError: " + msg);
    }

    @Override
    public void onActivityFinished() {
        if (LOGD) {
            Log.d(TAG,"onActivityFinished()");
        }
        finish(Activity.RESULT_OK,mResults);
    }

    @Override
    public void dumpIntermediateCoverage(String filePath) {
        if (LOGD) {
            Log.d(TAG,"Intermidate Dump Called with file name :" + filePath);
        }
        if (mCoverage){
            if (!setCoverageFilePath(filePath)) {
                if (LOGD) {
                    Log.d(TAG,"Unable to set the given file path :" +filePath + "as dump target.");
                }
            }
            generateCoverageReport();
            setCoverageFilePath(DEFAULT_COVERAGE_FILE_PATH);
        }
    }
}

  

2. Modify AndroidManifest.xml file, add the permission to read and write the phone, as well as instrument settings, and application of the tag label at the same level:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Jacoco权限 -->
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.READ_PROFILE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <instrumentation
        android:name="com.patech.test.JacocoInstrumentation"
        android:handleProfiling="true"
        android:label="CoverageInstrumentation"
        android:targetPackage="com.patech.testApp" />

3. Write jacoco.gradle, for parsing ec, or converted into other formats html report:

apply plugin: 'jacoco'
//https://docs.gradle.org/current/userguide/jacoco_plugin.html
jacoco {
    toolVersion = "0.8.4"
}
task jacocoTestReport(type: JacocoReport) {
    group = "Reporting"
    description = "Generate Jacoco coverage reports after running tests."
    def debugTree = fileTree(dir: "${buildDir}/intermediates/javac/debug",
//            includes: ["**/*Presenter.*"],
            excludes: ['**/R*.class',
                       '**/*$InjectAdapter.class',
                       '**/*$ModuleAdapter.class',
                       '**/*$ViewInjector*.class'
            ]) // specified class folder that contains the rules of the class and the class of the exclusionary rule, where we generate test reports for all classes Presenter
    def coverageSourceDirs = "${project.projectDir}/src/main/java" //指定源码目录
    def reportDirs="$buildDir/outputs/reports/jacoco/jacocoTestReport"
    reports {
        xml.enabled = true
        html.enabled = true
    }
//    destinationFile=file(reportDirs)
    classDirectories = files(debugTree)
    sourceDirectories = files(coverageSourceDirs)
    executionData = files("$buildDir/outputs/code-coverage/connected/coverage.ec")
}

4. Connect the phone, the statement after the implementation of adb install apk, open the application by jacoco:

adb shell am instrument -w -r com.patech.testApp / com.patech.testcoverage.test.JacocoInstrumentation

5. You can start to do a functional test on the phone, ec export file after the test is completed:

adb pull mnt/sdcard/coverage.ec C:\Users\user\Desktop\testReport\jacoco

6. ec file in build / outputs / code-coverage / connected at

 

 The task execution jacocoTestReport

 

 View resolved in build / reports / jacoco / jacocoTestReport report

 

View the report:

 

 

 

 

 

 

  

 

Guess you like

Origin www.cnblogs.com/zhizhiyin/p/11493392.html