<commit_before>Get test units coverage
======

Environment
------
> Espresso

> Android Studio

> Jacoco

How to do
-----
### Step1
In your build.gradle, enable testCoverage.
```groovy
android{
    compileSdkVersion 22
    buildToolsVersion "22.0.1"
    defaultConfig {
        applicationId 'com.six.practice'
        minSdkVersion 8
        targetSdkVersion 22
        versionCode 1
        VersionName '1.1'
        testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            testCoverageEnabled true
        }
    }
    packagingOptions {
        exclude('LICENSE.txt')
    }
}
```
However, you will find out all the data of coverage statistics is zero by running gradle task **createDebugCoverageReport**.
It seems that android\' DVM is not 100% compatible with JVM, so we need to move to another step.

### Step2
Write your own AndroidJUnitRunner and remember to use it in the build.gradle file, which mainly is used to reset the path of *coverage.ec* as well as to call *dump* method using reflection.
```java
public class JUnitJacocoTestRunner extends AndroidJUnitRunner {
    static {
        final String path = "/data/data/" + BuildConfig.APPLICATION_ID + "/coverage.ec";
        System.setProperty("jacoco-agent.destfile", path);
    }

    @Override
    public void finish(int resultCode, Bundle results) {
        try {
            Class rt = Class.forName("org.jacoco.agent.rt.RT");
            Method getAgent = rt.getMethod("getAgent");
            Method dump = getAgent.getReturnType().getMethod("dump", boolean.class);
            Object agent = getAgent.invoke(null);
            dump.invoke(agent, false);
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
```
ps:
1. The method *getAgent* is one static method of RunTime Class
![](/imgs/20160109_1.png)

2. The method *dump* belongs to interface IAgent, which is used to collect data, I guess.
![](/imgs/20160109_2.png)

### Step3
In the build.gradle, add _jacoco_ plugin and your JacocoReport task.
```groovy
apply plugin: 'jacoco'
jacoco {
    toolVersion "0.7.4.201502262128"
}

task jacocoTestReport(type:JacocoReport, dependsOn: "connectedAndroidTest"){<commit_msg>Update 2016-01-09-tools-jacoco.md<commit_after>Get test units coverage
======

Environment
------
> Espresso

> Android Studio

> Jacoco

How to do
-----
### Step1
In your build.gradle, enable testCoverage.
```groovy
android{
    compileSdkVersion 22
    buildToolsVersion "22.0.1"
    defaultConfig {
        applicationId 'com.six.practice'
        minSdkVersion 8
        targetSdkVersion 22
        versionCode 1
        VersionName '1.1'
        testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            testCoverageEnabled true
        }
    }
    packagingOptions {
        exclude('LICENSE.txt')
    }
}
```
However, you will find out all the data of coverage statistics is zero by running gradle task **createDebugCoverageReport**.
It seems that android\' DVM is not 100% compatible with JVM, so we need to move to another step.

### Step2
Write your own AndroidJUnitRunner and remember to use it in the build.gradle file, which mainly is used to reset the path of *coverage.ec* as well as to call *dump* method using reflection.
```java
public class JUnitJacocoTestRunner extends AndroidJUnitRunner {
    static {
        final String path = "/data/data/" + BuildConfig.APPLICATION_ID + "/coverage.ec";
        System.setProperty("jacoco-agent.destfile", path);
    }

    @Override
    public void finish(int resultCode, Bundle results) {
        try {
            Class rt = Class.forName("org.jacoco.agent.rt.RT");
            Method getAgent = rt.getMethod("getAgent");
            Method dump = getAgent.getReturnType().getMethod("dump", boolean.class);
            Object agent = getAgent.invoke(null);
            dump.invoke(agent, false);
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
```
ps:

1. The method *getAgent* is one static method of RunTime Class
![](/imgs/20160109_1.png)

2. The method *dump* belongs to interface IAgent, which is used to collect data, I guess.
![](/imgs/20160109_2.png)

### Step3
In the build.gradle, add _jacoco_ plugin and your JacocoReport task.
```groovy
apply plugin: 'jacoco'
jacoco {
    toolVersion "0.7.4.201502262128"
}

task jacocoTestReport(type:JacocoReport, dependsOn: "connectedAndroidTest"){
{'fraction_non_alphanumeric': 0.1026830744401856, 'fraction_numerical': 0.022997780915876537, 'mean_word_length': 2.825617283950617, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3289317', 'n_tokens_mistral': 1537, 'n_tokens_neox': 1417, 'n_words': 430}