Cobertura de código de Android en Firebase Test Lab (Parte 1: Conceptos básicos) | Autor: Aidan Lowe | Noviembre de 2021
Esta serie de artículos explicará cómo generar informes de cobertura de código para las pruebas de instrumentación de Android que se ejecutan en Firebase Test Lab.
Construiremos paso a paso, el objetivo final es lograr
- Genere informes XML y HTML para la cobertura de código probada en el dispositivo
- Se ejecuta en dispositivos API 30 en Firebase Test Lab
- Admite aplicaciones de Android para API 30
- Admite aplicaciones de varios módulos
- Combinar resultados con pruebas unitarias fuera del dispositivo
- Filtre el código generado de Room, Moshi, Dagger y View Binding
- Combinar con flancos
- Utilice scripts para ejecutar en la canalización de CI / CD
Los siguientes artículos se establecerán para cumplir con todos los requisitos mencionados, pero por ahora nos centraremos en estos requisitos:
- Genere informes XML y HTML para la cobertura de la prueba
- Ejecuta pruebas en dispositivos API 28 en Firebase Test Lab
- Admite aplicaciones orientadas a API 28
Empezaremos con una API 2 muy sencilla8 Para la aplicación, inicie un nuevo proyecto de Android en Android Studio Arctic Fox sin ninguna actividad y luego edite build.gradle a nivel de proyecto para crearlo para API 28. Agregaremos una clase Java y una clase Kotlin, cada una con dos métodos, y agregaremos una prueba de instrumentación que llamará a un método en cada clase.
Si observa el envío inicial, puede verlo en https://github.com/Aidan128/CoverageExample1.
Puedes construirlo fácilmente
./gradlew clean assembleDebug assembleDebugAndroidTest
Este artículo asume que ya ha configurado Firebase Test Lab para la ejecución de la línea de comandos. De lo contrario, siga las instrucciones en https://firebase.google.com/docs/test-lab/android/command-line
Una vez que esté listo para usar la herramienta de línea de comandos de Google Cloud, solo necesita ejecutar el comando correcto. (Gracias a Satyajit Malugu)
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/coverage.ec
--directories-to-pull /sdcard
Si observa la salida, verá una línea que se parece a
Raw results will be stored in your GCS bucket at [https://console.developers.google.com/storage/browser/test-lab-//]
Si hace clic en el enlace, se le dirigirá a una página que se parece a
Si hace clic en el vínculo del dispositivo que usamos (Pixel2–28-en-portrait), se encontrará en una página que se ve así
Entonces, si hace clic en el enlace instrumentation.results
Se le dirigirá a una página donde podrá descargar el contenido del archivo.Debería verse como
Si hace clic en el enlace «Descargar» y se desplaza hasta la parte inferior, verá los resultados de nuestro intento de generar un informe de cobertura de código …
Error: Failed to generate Emma/JaCoCo coverage. Is Emma/JaCoCo jar on classpath?
Oh.
Parece que no habilitamos la cobertura de código en nuestra compilación.Necesitamos abrirlo agregando testCoverageEnabled
En build.gradle a nivel de módulo. Lo activaremos para todas las versiones de depuración, aunque también puede usar el mecanismo tradicional de gradle para solicitar a los usuarios que pasen una marca en el momento de la compilación para habilitarlo, si lo desea.
buildTypes {
debug {
testCoverageEnabled true
}
}
Una vez que abrimos, haga una compilación limpia y ejecute el comando gcloud nuevamente instrumentation.results
De nuevo vemos
Error: Failed to generate Emma/JaCoCo coverage.
Necesitamos abrir logcat para ver exactamente qué sucedió, por lo que haremos clic en el enlace logcat en el mismo lugar donde se encontró el enlace instrumentation.results, haga clic en descargar y luego buscaremos «jacoco» en el archivo de logcat.Donde encontramos
11-28 10:06:39.384: E/CoverageListener(7274): Failed to generate Emma/JaCoCo coverage.
11-28 10:06:39.384: E/CoverageListener(7274): java.lang.reflect.InvocationTargetException
11-28 10:06:39.384: E/CoverageListener(7274): at java.lang.reflect.Method.invoke(Native Method)
11-28 10:06:39.384: E/CoverageListener(7274): at androidx.test.internal.runner.listener.CoverageListener.generateCoverageReport(CoverageListener.java:101)
11-28 10:06:39.384: E/CoverageListener(7274): at androidx.test.internal.runner.listener.CoverageListener.instrumentationRunFinished(CoverageListener.java:70)
11-28 10:06:39.384: E/CoverageListener(7274): at androidx.test.internal.runner.TestExecutor.reportRunEnded(TestExecutor.java:92)
11-28 10:06:39.384: E/CoverageListener(7274): at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:65)
11-28 10:06:39.384: E/CoverageListener(7274): at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:395)
11-28 10:06:39.384: E/CoverageListener(7274): at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
11-28 10:06:39.384: E/CoverageListener(7274): Caused by: java.io.FileNotFoundException: /sdcard/coverage.ec (Permission denied)
11-28 10:06:39.384: E/CoverageListener(7274): at java.io.FileOutputStream.open0(Native Method)
11-28 10:06:39.384: E/CoverageListener(7274): at java.io.FileOutputStream.open(FileOutputStream.java:308)
11-28 10:06:39.384: E/CoverageListener(7274): at java.io.FileOutputStream.(FileOutputStream.java:238)
11-28 10:06:39.384: E/CoverageListener(7274): at com.vladium.emma.rt.RT.dumpCoverageData(RT.java:50)
11-28 10:06:39.384: E/CoverageListener(7274): ... 7 more
La clave aquí es java.io.FileNotFoundException: /sdcard/coverage.ec (Permission denied)
. El agente de jacoco está intentando escribir el archivo coberturas.ec /sdcard
, Pero no tiene derecho a hacerlo.
La solución es otorgar el permiso WRITE_EXTERNAL_STORAGE en AndroidManifest.xml. (Crearemos un nuevo AndroidManifest.xml
existe app/src/debug/AndroidManifest.xml
De esta forma no afectaremos la versión de producción de la aplicación)
Por última vez, ejecutaremos gcloud, y ahora instrumentation.results muestra que lo hemos logrado.
Generated code coverage data to /sdcard/coverage.ec
Si miramos hacia atrás en Google Cloud Storage (en el mismo lugar donde vimos los enlaces instrumentation.results y logcat), ahora hay una carpeta «artifacts» que contiene coverage.ec
, Así que hemos completado nuestra primera mitad.
esta gsutil
La utilidad nos permite copiar archivos fácilmente desde ella. gs://
Enlace, podemos usar la URL del depósito de resultados de GCS para calcular el enlace.
Por ejemplo, si la URL del depósito de resultados de GCS es
https://console.developers.google.com/storage/browser//
Entonces el enlace gs: // del archivo coberturas.ec es
gs:////Pixel2-28-en-portrait/artifacts/coverage.ec
Podemos descargarlo emitiendo el comando gsutil
gsutil cp gs:////Pixel2-28-en-portrait/artifacts/coverage.ec .
Sin embargo, los archivos .ec no son adecuados para uso humano. Dado que nuestro objetivo es crear informes XML y HTML para ver la información de cobertura, necesitamos utilizar las actividades de generación de informes de JaCoCo.A diferencia del soporte para detectar archivos binarios (siempre que pase testCodeCoverage
), si queremos generar informes para cualquier archivo .ec obtenido externamente, necesitamos definir claramente la dependencia de JaCoCo en nuestro build.gradle a nivel de proyecto:
En nuestro build.gradle a nivel de módulo, también necesitamos agregar una dependencia en el complemento JaCoCo y agregar una tarea personalizada para generar el informe.
Una vez que todos estos estén en su lugar, podemos generar un informe llamando
./gradlew jacocoExternalTestReport
Luego puede abrir el informe que se encuentra en la siguiente ubicación app/build/reports/jacoco/jacocoExternalTestReport/html/index.html
En este punto, hemos alcanzado los objetivos y requisitos de este artículo. Mirando hacia atrás, estos son los pasos necesarios para llegar aquí:
- poner
testCoverageEnabled true
Se utiliza para la versión de depuración para habilitar la cobertura del código. - añadir
WRITE_EXTERNAL_STORAGE
Permiso para permitir la versión de depuracióncoverage.ec
Escriba la sdcard del dispositivo de prueba - usar
gsutil
ir a descargarcoverage.ec
Desde el depósito de resultados - Agregar una dependencia de jacoco a nivel de proyecto y de aplicación
build.gradle
documento. - Agregue una nueva tarea de Gradle para generar informes desde cualquier archivo .ec.
Al mirar https://github.com/Aidan128/CoverageExample1 y observar la confirmación más reciente, puede ver la solución que combina todos estos cambios.
Esto cumple con nuestros requisitos básicos para este artículo, pero aún nos queda un largo camino por recorrer. En particular, los nuevos mecanismos de seguridad que rodean el almacenamiento en API 30 plantean desafíos especiales que estudiaremos a continuación.
Muchas personas han escrito artículos sobre este tema en el pasado y sus artículos han sido de gran ayuda para mi investigación. Les doy las gracias.