Ejecutar pruebas JUnit simples en Android Studio (IntelliJ) cuando se usa una configuración basada en Gradle

78

Estoy usando Android Studio/IntelliJpara construir sobre un Androidproyecto existente y me gustaría agregar algunas JUnitpruebas unitarias simples . ¿Cuál es la carpeta correcta para agregar tales pruebas?

El Gradlecomplemento de Android define una estructura de directorio src/main/javapara el código fuente principal y src/instrumentTest/javapara las Androidpruebas.

Intentar agregar mis pruebas JUnit en instrumentTest no funcionó para mí. Puedo ejecutarlo como una Androidprueba (eso es lo que parece ese directorio) pero eso no es lo que estoy buscando, solo quiero ejecutar una JUnitprueba simple . Intenté crear una configuración de ejecución JUnit para esta clase, pero tampoco funcionó; supongo que porque estoy usando un directorio que está marcado como AndroidPrueba en lugar de Fuente.

Si creo una nueva carpeta de origen y la marco como tal en la Estructura del proyecto, esto se borrará la próxima vez que IntelliJactualice la configuración del proyecto desde los archivos de compilación de Gradle.

¿Cuál es la forma más adecuada de configurar las pruebas de JUnit en un proyecto de Android basado en gradle IntelliJ? ¿Qué estructura de directorio usar para esto?

Julián Cerruti
fuente
Desafortunadamente, no puedo ayudarlo con las pruebas ya que todavía estoy luchando con esto yo mismo, pero puede usar esto para evitar que IntelliJ borre las carpetas de origen: java.srcDirs = ['src/main/java','src/instrumentTest/java']en la sourceSetssección delbuild.gradle
Rob Holmes
No es divertido de configurar, ni simple de mantener, pero de alguna manera lo puse en ejecución usando la /src/androidTest/javacarpeta predeterminada con pruebas de JUnit robolectric, ver: stackoverflow.com/a/25473702/1406325
Flo
Android Studio ahora admite pruebas de unidades locales con JUnit 4: stackoverflow.com/a/30273301/885464
Lorenzo Polidori
@Julian Cerruti Actualización: Android Studio Demo para cómo ejecutar caso_prueba goo.gl/ac06C0 y ejemplo para ejecutar la llamada red de prueba goo.gl/bQFlmU
nitesh
Las estructuras de directorios para pruebas y clases probadas deben encajar. Aquí se explica cómo hacerlo fácilmente: stackoverflow.com/a/36057080/715269
Gangnus

Respuestas:

23

A partir de Android Studio 1.1, la respuesta ahora es simple: http://tools.android.com/tech-docs/unit-testing-support

Erik B
fuente
4
¿Significa esto que Robolectric ya no es útil? ¿Esto esencialmente hará lo mismo?
David Argyle Thacker
1
Nota: A partir de Android Studio 2.0 Beta5, falta el selector "Test Artifact" en el enlace que describe y ambos modos (junit & insttrumentation) están habilitados simultáneamente de forma predeterminada. Consulte aquí para obtener más información stackoverflow.com/questions/35708263/…
Patrick Favre
36

Normalmente, no puedes. Bienvenido al mundo de Android, donde todas las pruebas deben ejecutarse en un dispositivo (excepto Robolectric).

La razón principal es que en realidad no tiene las fuentes del marco; incluso si convence al IDE de que ejecute la prueba localmente, obtendrá inmediatamente una excepción "Stub! No implementado". "¿Por qué?" te preguntarás Porque lo android.jarque le brinda el SDK en realidad está desactivado: todas las clases y métodos están allí, pero todos simplemente lanzan una excepción. Está ahí para proporcionar una API, pero no para ofrecerle una implementación real.

Hay un proyecto maravilloso llamado Robolectric que implementa gran parte del marco solo para que puedas ejecutar pruebas significativas. Junto con un buen marco simulado (por ejemplo, Mockito), hace que su trabajo sea manejable.

Complemento de Gradle: https://github.com/robolectric/robolectric-gradle-plugin

Delyan
fuente
1
Gracias, Deylan. Estoy detrás de pruebas simples que no usan ninguna infraestructura de Android, por lo que crear un nuevo proyecto como usted sugiere o ajustar la configuración de Gradle Android para adaptarse a las pruebas regulares será el camino a seguir. Desafortunadamente, todavía no pude hacer que funcionara, sigue fallando por una razón u otra, pero publicaré el resultado si alguna vez lo hago funcionar
Julian Cerruti
1
En ese caso, desea crear un nuevo proyecto Java Gradle simple (es decir apply plugin: 'java'), agregarlo a 'settings.gradle', tenerlo como una dependencia para su proyecto de Android ( compile project(':plainJavaProjectName')) y simplemente ejecutar la testtarea. (¡No probado, pero definitivamente debería funcionar!)
Delyan
3
Las pruebas en un proyecto simple de Java Gradle funcionan bien con la línea de comandos, pero no dentro de Android Studio, donde aparece el error "class not found MyTestClass". Eso es extraño porque AS y la línea de comandos deberían usar gradle de la misma manera.
lukas
1
Evite gradle si desea utilizar las pruebas de JUnit, maven es una mejor opción.
Jeroen
3
¿Puede justificar esa afirmación? ¿Por qué Maven es mejor?
RichieHH
32

Intro

Tenga en cuenta que en el momento de escribir este artículo, robolectric 2.4 es la última versión y no tiene soporte para la appcompat v7biblioteca. Se agregará soporte en la versión robolectric 3.0 ( aún sin ETA ). También ActionBar Sherlockpuede causar problemas con robolectric.

Para usar Robolectric dentro de Android Studio tienes 2 opciones:

(Opción 1): ejecutar pruebas JUnit con Android Studio usando un módulo Java

Esta técnica utiliza un módulo de Java para todas sus pruebas con una dependencia a su módulo de Android y un corredor de prueba personalizado con algo de magia:

Las instrucciones se pueden encontrar aquí: http://blog.blundellapps.com/how-to-run-robolectric-junit-tests-in-android-studio/

También verifique el enlace al final de esa publicación para ejecutar las pruebas desde Android Studio.

(Opción 2) - Ejecutar pruebas JUnit con Android Studio usando robolectric-gradle-plugin

Encontré algunos problemas al configurar las pruebas junit para que se ejecuten desde gradle en Android Studio.

Este es un proyecto de muestra muy básico para ejecutar pruebas junit desde un proyecto basado en gradle en Android Studio: https://github.com/hanscappelle/android-studio-junit-robolectric Esto se probó con Android Studio 0.8.14, JUnit 4.10, complemento Gradle robolectric 0.13+ y robolectric 2.3

Buildscript (proyecto / build.gradle)

El script de compilación es el archivo build.gradle en la raíz de su proyecto. Allí tuve que agregar el complemento Gradle robolectric a classpath

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.13.2'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        classpath 'org.robolectric:robolectric-gradle-plugin:0.13.+'

    }
}

allprojects {
    repositories {
        jcenter()
    }
}

Proyecto buildscript (App / build.gradle)

En el script de compilación del módulo de su aplicación, use el robolectriccomplemento, agregue la robolectricconfiguración y agregue las androidTestCompiledependencias.

apply plugin: 'com.android.application'
apply plugin: 'robolectric'

android {
    // like any other project
}

robolectric {
    // configure the set of classes for JUnit tests
    include '**/*Test.class'
    exclude '**/espresso/**/*.class'

    // configure max heap size of the test JVM
    maxHeapSize = '2048m'

    // configure the test JVM arguments
    jvmArgs '-XX:MaxPermSize=512m', '-XX:-UseSplitVerifier'

    // configure whether failing tests should fail the build
    ignoreFailures true

    // use afterTest to listen to the test execution results
    afterTest { descriptor, result ->
        println "Executing test for {$descriptor.name} with result: ${result.resultType}"
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    androidTestCompile 'org.robolectric:robolectric:2.3'
    androidTestCompile 'junit:junit:4.10'
}

Crear clases de prueba JUnit

Ahora coloque las clases de prueba en la ubicación predeterminada (o actualice la configuración de gradle)

app/src/androidTest/java

Y asigne un nombre a sus clases de pruebas que terminen con Test (o actualice nuevamente la configuración), ampliando junit.framework.TestCasey anote los métodos de prueba con @Test.

package be.hcpl.android.mytestedapplication;

import junit.framework.TestCase;
import org.junit.Test;

public class MainActivityTest extends TestCase {

    @Test
    public void testThatSucceeds(){
        // all OK
        assert true;
    }

    @Test
    public void testThatFails(){
        // all NOK
        assert false;
    }
}

Ejecutar pruebas

Luego, ejecute las pruebas usando gradlew desde la línea de comando (hágalo ejecutable usando chmod +xsi es necesario)

./gradlew clean test

Salida de muestra:

Executing test for {testThatSucceeds} with result: SUCCESS
Executing test for {testThatFails} with result: FAILURE

android.hcpl.be.mytestedapplication.MainActivityTest > testThatFails FAILED
    java.lang.AssertionError at MainActivityTest.java:21

2 tests completed, 1 failed                                  
There were failing tests. See the report at: file:///Users/hcpl/Development/git/MyTestedApplication/app/build/test-report/debug/index.html
:app:test                      

BUILD SUCCESSFUL

Solución de problemas

directorios de fuentes alternativas

Al igual que puede tener sus archivos fuente de Java en otro lugar, puede mover sus archivos fuente de prueba. Simplemente actualice la sourceSetsconfiguración de gradle .

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        androidTest {
            setRoot('tests')
        }
    }

el paquete org.junit no existe

Olvidó agregar la dependencia de prueba junit en el script de compilación de la aplicación

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    androidTestCompile 'org.robolectric:robolectric:2.3'
    androidTestCompile 'junit:junit:4.10'
}

java.lang.RuntimeException: Stub!

Está ejecutando esta prueba con las configuraciones de ejecución de Android Studio en lugar de la línea de comandos (pestaña Terminal en Android Studio). Para ejecutarlo desde Android Studio, deberá actualizar el app.imlarchivo para que la entrada jdk aparezca en la parte inferior. Consulte el ejemplo de deckard-gradle para obtener más detalles.

Ejemplo de error completo:

!!! JUnit version 3.8 or later expected:

java.lang.RuntimeException: Stub!
    at junit.runner.BaseTestRunner.<init>(BaseTestRunner.java:5)
    at junit.textui.TestRunner.<init>(TestRunner.java:54)
    at junit.textui.TestRunner.<init>(TestRunner.java:48)
    at junit.textui.TestRunner.<init>(TestRunner.java:41)
    at com.intellij.rt.execution.junit.JUnitStarter.junitVersionChecks(JUnitStarter.java:190)
    at com.intellij.rt.execution.junit.JUnitStarter.canWorkWithJUnitVersion(JUnitStarter.java:173)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:56)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

ERROR: JAVA_HOME está configurado en un directorio no válido

Consulte esta pregunta SO para obtener una solución. Agregue la siguiente exportación a su perfil de bash:

export JAVA_HOME=`/usr/libexec/java_home -v 1.7`  

El registro de errores completo:

ERROR: JAVA_HOME is set to an invalid directory: export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation.

Clase de prueba no encontrada

Si desea ejecutar sus pruebas desde Android Studio Junit Test runner, tendrá que expandir el archivo build.gradle un poco más para que Android Studio pueda encontrar sus clases de prueba compiladas:

sourceSets {
    testLocal {
        java.srcDir file('src/test/java')
        resources.srcDir file('src/test/resources')
    }
}

android {

    // tell Android studio that the instrumentTest source set is located in the unit test source set
    sourceSets {
        instrumentTest.setRoot('src/test')
    }
}

dependencies {

    // Dependencies for the `testLocal` task, make sure to list all your global dependencies here as well
    testLocalCompile 'junit:junit:4.11'
    testLocalCompile 'com.google.android:android:4.1.1.4'
    testLocalCompile 'org.robolectric:robolectric:2.3'

    // Android Studio doesn't recognize the `testLocal` task, so we define the same dependencies as above for instrumentTest
    // which is Android Studio's test task
    androidTestCompile 'junit:junit:4.11'
    androidTestCompile 'com.google.android:android:4.1.1.4'
    androidTestCompile 'org.robolectric:robolectric:2.3'

}

task localTest(type: Test, dependsOn: assemble) {
    testClassesDir = sourceSets.testLocal.output.classesDir

    android.sourceSets.main.java.srcDirs.each { dir ->
        def buildDir = dir.getAbsolutePath().split('/')
        buildDir =  (buildDir[0..(buildDir.length - 4)] + ['build', 'classes', 'debug']).join('/')

        sourceSets.testLocal.compileClasspath += files(buildDir)
        sourceSets.testLocal.runtimeClasspath += files(buildDir)
    }

    classpath = sourceSets.testLocal.runtimeClasspath
}

check.dependsOn localTest

de: http://kostyay.name/android-studio-robolectric-gradle-getting-work/

Algunos recursos más

Los mejores artículos que encontré sobre esto son:

hcpl
fuente
0

Consulte este tutorial del sitio oficial de desarrolladores de Android. Este artículo también muestra cómo crear maquetas para sus pruebas.

Por cierto, debe tener en cuenta que el alcance de las dependencias para la prueba JUnit simple debe ser "testCompile".

BlueMice
fuente