Blog Infos
Author
Published
Topics
,
Author
Published
Final goal
Requirements for Part 1
Getting started with API 28
public class JavaClass {
int function1() {
return 2 + 2;
}
int function2() {
return 3 + 3;
}
}
view raw JavaClass.java hosted with ❤ by GitHub
class KotlinClass {
fun function1(): Int =
2 + 2
fun function2(): Int =
3 + 3
}
view raw KotlinClass.kt hosted with ❤ by GitHub
@RunWith(AndroidJUnit4::class)
class Tests {
@Test
fun basicTests() {
assertEquals(4, JavaClass().function1())
assertEquals(4, KotlinClass().function1())
}
}
view raw Tests.kt hosted with ❤ by GitHub
Building and running
gcloud firebase test android run \
--type instrumentation \
--no-performance-metrics \
--no-record-video \
--app app/build/outputs/apk/debug/app-debug.apk \
--test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
--device model=Pixel2,version=28,locale=en,orientation=portrait \
--environment-variables coverage=true,coverageFile=/sdcard/Download/coverage.ec \
--directories-to-pull /sdcard/Download
Raw results will be stored in your GCS bucket at [https://console.developers.google.com/storage/browser/test-lab-<project-id>/<timestamp>/]

If you follow the link you’ll come to a page that looks like

 

And then if you click the link for instrumentation.results you’ll come to a page where you can download the contents of the file. It should look something like

 

And if you click the “download” link and scroll to the bottom, you’ll see the results of our attempt to generate a code coverage report…

Error: Failed to generate Emma/JaCoCo coverage. Is Emma/JaCoCo jar on classpath?
Enabling code coverage
buildTypes {
    debug {
        testCoverageEnabled (project.hasProperty('coverage'))
    }
}
Error: Failed to generate Emma/JaCoCo coverage.
E/CoverageListener(6620): Failed to generate Emma/JaCoCo coverage. 
E/CoverageListener(6620): java.lang.reflect.InvocationTargetException
E/CoverageListener(6620): 	at java.lang.reflect.Method.invoke(Native Method)
E/CoverageListener(6620): 	at androidx.test.internal.runner.listener.CoverageListener.generateCoverageReport(CoverageListener.java:101)
E/CoverageListener(6620): 	at androidx.test.internal.runner.listener.CoverageListener.instrumentationRunFinished(CoverageListener.java:70)
E/CoverageListener(6620): 	at androidx.test.internal.runner.TestExecutor.reportRunEnded(TestExecutor.java:92)
E/CoverageListener(6620): 	at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:65)
E/CoverageListener(6620): 	at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:395)
E/CoverageListener(6620): 	at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
E/CoverageListener(6620): Caused by: java.io.FileNotFoundException: /sdcard/Download/coverage.ec (Permission denied)
Granting permission
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.aidan128.coverage1">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>

Job Offers

Job Offers


    Android Build Engineer

    Pinterest
    San Francisco, CA | Seattle, WA
    • Full Time
    apply now

    Android Developer

    Small and Modern GmbH
    Hamburg, Remote (Germany)
    • Full Time
    apply now

    Senior Android Developer (Remote)

    Komoot
    Europe
    • Full Time
    apply now
Load more listings

OUR VIDEO RECOMMENDATION

,

Leveling Up Your Tests

We all know about TDD and Unit Testing, and even screenshot testing, but sometimes we do not need to embrace a new paradigm to make our tests better. These are several techniques I have adopted…
Watch Video

Leveling Up Your Tests

Jobs

One final time, we’ll run gcloud, and now instrumentation.results shows that we’ve succeeded!

Generated code coverage data to /sdcard/Download/coverage.ec

If we look back in Google Cloud Storage (in the same location we saw the instrumentation.results and logcat links) there is now an “artifacts” folder that contains coverage.ec, at last.

 

Supporting Android 10 (API 29)
android {
    compileSdk 29
    defaultConfig {
        targetSdk 29
        ...
    }
    ...
}
gcloud firebase test android run \
--type instrumentation \
--no-performance-metrics \
--no-record-video \
--app app/build/outputs/apk/debug/app-debug.apk \
--test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
--device model=Pixel2,version=29,locale=en,orientation=portrait \
--environment-variables coverage=true,coverageFile=/sdcard/Download/coverage.ec \
--directories-to-pull /sdcard/Download

However, when we run the gcloud command now instrumentation.resultsreports

Error: Failed to generate Emma/JaCoCo coverage

and logcat contains

E/CoverageListener(10124): Failed to generate Emma/JaCoCo coverage. 
E/CoverageListener(10124): java.lang.reflect.InvocationTargetException
E/CoverageListener(10124): 	at java.lang.reflect.Method.invoke(Native Method)
E/CoverageListener(10124): 	at androidx.test.internal.runner.listener.CoverageListener.generateCoverageReport(CoverageListener.java:101)
E/CoverageListener(10124): 	at androidx.test.internal.runner.listener.CoverageListener.instrumentationRunFinished(CoverageListener.java:70)
E/CoverageListener(10124): 	at androidx.test.internal.runner.TestExecutor.reportRunEnded(TestExecutor.java:92)
E/CoverageListener(10124): 	at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:65)
E/CoverageListener(10124): 	at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:395)
E/CoverageListener(10124): 	at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2189)
E/CoverageListener(10124): Caused by: java.io.FileNotFoundException: /sdcard/Download/coverage.ec: open failed: EACCES (Permission denied)

The problem is that API 29 introduces new restrictions on where applications can write to. (“scoped storage”) Luckily, we can easily opt out by adding requestLegacyExternalStorage to app/src/debug/AndroidManifest.xml.

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.aidan128.coverage1">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:requestLegacyExternalStorage="true"
/>
</manifest>
Supporting Android 11 (API 30)
android {
    compileSdk 30

    defaultConfig {
        targetSdk 30
        ...
    }
    ...
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.aidan128.coverage1">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"/>
<application
android:requestLegacyExternalStorage="true"
/>
</manifest>
Downloading the .ec file
https://console.developers.google.com/storage/browser/<project-id>/<timestamp>

then the gs:// link for the coverage.ec file (for our chosen device) is

gs://<project-id>/<timestamp>/Pixel2-30-en-portrait/artifacts/coverage.ec

And we can download it by issuing the gsutil command. We’ll put it into app/build/outputs/coverage for now.

mkdir app/build/outputs/coverage
gsutil cp gs://<project-id>/<timestamp>/Pixel2-30-en-portrait/artifacts/coverage.ec app/build/outputs/coverage
Building reports from external .ec files
dependencies {
classpath "org.jacoco:org.jacoco.core:0.8.7"
}
view raw build.gradle hosted with ❤ by GitHub

In our module-level build.gradle, we’ll also need to add a dependency on the JaCoCo plugin as well as add a custom task to build the report.

plugins {
id 'jacoco'
}
...
task jacocoReport(type: JacocoReport) {
group "Coverage"
description "Generate XML/HTML code coverage reports for coverage.ec"
reports {
xml.enabled = true
html.enabled = true
}
getSourceDirectories().setFrom("${project.projectDir}/src/main/java")
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
getClassDirectories().setFrom(
fileTree(dir: "${buildDir}/intermediates/javac/debug", excludes: fileFilter),
fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: fileFilter))
getExecutionData().setFrom(
fileTree(dir: "${buildDir}/outputs/code_coverage", includes: ['*.ec']))
}
view raw gistfile1.txt hosted with ❤ by GitHub
./gradlew jacocoReport

and then can open the report found at app/build/reports/jacoco/jacocoReport/html/index.html

TL;DR
Next time
Special thanks

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Every good Android application should be well tested to minimize the risk of error…
READ MORE
blog

Running Instrumented Tests in a Gradle task

During the latest Google I/O, a lot of great new technologies were shown. The…
READ MORE
blog
Notifications are a very important part of Android apps, showing relevant information, informing when…
READ MORE

Leave a Reply

Your email address will not be published.

Fill out this field
Fill out this field
Please enter a valid email address.

Menu