Prueba unitaria de Android Studio: archivo de datos de lectura (entrada)

96

En una prueba unitaria, ¿cómo puedo leer datos de un archivo json en mi sistema de archivos (escritorio), sin codificar la ruta?

Me gustaría leer la entrada de prueba (para mis métodos de análisis) de un archivo en lugar de crear cadenas estáticas.

El archivo está en la misma ubicación que mi código de prueba de unidad, pero también puedo colocarlo en otro lugar del proyecto si es necesario. Estoy usando Android Studio.

Franco
fuente
3
Probé casi todas las combinaciones con IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8"), siempre devuelve nulo. Probablemente porque los archivos no se incluirán en el jar.
Frank
¿Estamos hablando de pruebas unitarias que involucran un emulador / dispositivo Android?
AndroidEx
@ Android777 Creo que estamos hablando de un nuevo soporte de prueba unitario introducido en la versión reciente de Android Studio tools.android.com/tech-docs/unit-testing-support
akhy
@Frank ¿dónde lo colocas test_documents.json? directorio de activos?
akhy
Sí, estamos hablando del nuevo soporte de prueba unitaria, que no involucra al emulador / dispositivo. No lo coloqué en el directorio de activos, porque luego se empaqueta con la apk en vivo. Lo coloqué en la misma carpeta que los archivos de prueba (java).
Frank

Respuestas:

149

Dependiendo de la android-gradle-pluginversión:

1. versión 1.5 y superior:

Simplemente coloque el archivo json src/test/resources/test.jsony haga referencia a él como

classLoader.getResource("test.json"). 

No se necesita ninguna modificación de Gradle.

2. versión inferior a 1.5 : (o si por alguna razón la solución anterior no funciona)

  1. Asegúrese de que está utilizando al menos la versión 1.1 del complemento Gradle de Android . Siga el enlace para configurar Android Studio correctamente.

  2. Crear testdirectorio. Coloque las clases de prueba unitaria en el javadirectorio y coloque su archivo de recursos en el resdirectorio. Android Studio debería marcarlos como sigue:

    ingrese la descripción de la imagen aquí

  3. Cree una gradletarea para copiar recursos en el directorio de clases para hacerlos visibles para classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
    
  4. Ahora puede usar este método para obtener una Filereferencia para el recurso de archivo:

    private static File getFileFromPath(Object obj, String fileName) {
        ClassLoader classLoader = obj.getClass().getClassLoader();
        URL resource = classLoader.getResource(fileName);
        return new File(resource.getPath());
    }
    
    @Test
    public void fileObjectShouldNotBeNull() throws Exception {
        File file = getFileFromPath(this, "res/test.json");
        assertThat(file, notNullValue());
    }
    
  5. Ejecute la prueba unitaria por Ctrl+ Shift+ F10en toda la clase o método de prueba específico.
klimat
fuente
1
¡Increíble! Tu edición, sin pruebas instrumentales, funciona como un encanto, ¡gracias!
Frank
4
Es una buena solución, pero no siempre funciona. Si realiza, ejecute la tarea de limpieza y luego ejecute testDebug, fallará. Básicamente, el desarrollador necesita saber que debe ejecutar la tarea ensamblarDebug antes de probarDebug. ¿Tienen alguna sugerencia para mejorar esto?
joaoprudencio
18
Con AndroidStudio 1.5 con el complemento de Android 1.5.0, coloque su archivo json aquí src/test/resources/test.jsony haga referencia a él como classLoader.getResource("test.json"). No se necesita ninguna modificación de Gradle. Las carpetas anidadas en el interior resourcestambién funcionan.
Sergii Pechenizkyi
6
Respuesta incompleta. ¿Qué es classLoader? ¿Dónde colocar esta línea de código? ¿Qué puedes hacer con el resultado devuelto? Proporcione un código más completo. -1
voghDev
3
Para leer ./src/test/resources/file.txten Kotlin:TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik
76

Para las pruebas de unidades locales (frente a las pruebas de instrumentación), puede colocar archivos debajo src/test/resourcesy leerlos usando classLoader. Por ejemplo, el siguiente código abre un myFile.txtarchivo en el directorio de recursos.

InputStream in = this.getClass().getClassLoader().getResourceAsStream("myFile.txt");

Funcionó con

  • Android Studio 1.5.1
  • complemento de gradle 1.3.1
usuario3113045
fuente
Esto no funciona para mí, consulte mi pregunta aquí stackoverflow.com/questions/36295824/…
Tyler Pfaff
5
Esto funcionó para mí, cuando cambié de "src / test / res" a "src / test / resources". Usando Android Studio 2.0 RC 3, gradle: 2.0.0-rc3
Alex Bravo
funcionó como se esperaba. Pero la prueba está pasando incluso si el archivo no está disponible en "src / test / resources /", por ejemplo: "rules.xml", pero InputStream resulta nulo en este caso.
anand krish
4
kotlin:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj.
¡Funcionó a las mil maravillas!
Amit Bhandari
15

En mi caso, la solución fue agregar al archivo gradle

sourceSets {
    test.resources.srcDirs += 'src/unitTests/resources'
  } 

Después de eso, todo fue encontrado por AS 2.3.1

javaClass.classLoader.getResourceAsStream("countries.txt")
ar-g
fuente
Hice algo muy similar (Kotlin): 1. crear carpeta y archivo en: root/app/src/test/resources/test.json 2. leer datos como este:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj.
8

Tuve muchos problemas con los recursos de prueba en Android Studio, así que configuré algunas pruebas para mayor claridad. En mi proyecto mobile(Aplicación de Android) agregué los siguientes archivos:

mobile/src/test/java/test/ResourceTest.java
mobile/src/test/resources/test.txt
mobile/src/test/resources/test/samePackage.txt

La clase de prueba (todas las pruebas pasan):

assertTrue(getClass().getResource("test.txt") == null);
assertTrue(getClass().getResource("/test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getResource("samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getResource("/test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getClassLoader().getResource("test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getClassLoader().getResource("test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));

En el mismo proyecto raíz tengo un proyecto de Java (no de Android) llamado data. Si agrego los mismos archivos al proyecto de datos:

data/src/test/java/test/ResourceTest.java
data/src/test/resources/test.txt
data/src/test/resources/test/samePackage.txt

Entonces, todas las pruebas anteriores fallarán si las ejecuto desde Android Studio, pero pasan la línea de comando con ./gradlew data:test. Para evitarlo, uso este truco (en Groovy)

def resource(String path) {
    getClass().getResource(path) ?:
            // Hack to load test resources when executing tests from Android Studio
            new File(getClass().getClassLoader().getResource('.').path
                    .replace('/build/classes/test/', "/build/resources/test$path"))
}

Uso: resource('/test.txt')

Android Studio 2.3, Gradle 3.3

Amor
fuente
Gran respuesta (después de 45 minutos de búsqueda 😌). Llega al meollo de varios problemas y facilita la replicación de los resultados utilizando las propias pruebas. Fwiw, en AS 2.3.1, Gradle 2.3.1, las getClassLoader()versiones funcionan como se esperaba. Es decir, encuentran los archivos, ambos se ejecutan desde Android Studio Y desde la línea de comando en mi máquina macOS, y en el servidor CI de Linux (CircleCI). Así que voy con eso y espero que Gradle 3.3 no lo rompa más tarde ...
mm2001
¡Agradable! Veo el mismo problema de carga de recursos aquí. COMO 2.3.2, Gradle 3.3. Las pruebas funcionan desde la línea de comandos pero no a través de AS, debido a que build/resources/testno están incluidas en la ruta de clases interactiva.
Mark McKenna
6

Si va a Ejecutar -> Editar configuraciones -> JUnit y luego selecciona la configuración de ejecución para sus pruebas unitarias, hay una configuración de 'Directorio de trabajo'. Eso debería apuntar a donde sea que esté su archivo json. Tenga en cuenta que esto podría romper otras pruebas.

Tas Morf
fuente
y luego usar this.getClass (). getResourceAsStream (test.json)? Agregué los archivos allí, en la raíz del proyecto, todavía no encuentra los archivos.
Frank
Esto se puede usar para cargar archivos usando new File()o similar, pero no funciona directamente con el método de carga de classpath descrito anteriormente. También es un poco complicado porque cada nueva configuración de ejecución necesita establecer el directorio de trabajo y, de forma predeterminada, a la línea de comandos de AS y Gradle les gusta usar diferentes directorios de trabajo ... un dolor
Mark McKenna
4

Pensé que debería agregar mis hallazgos aquí. Sé que esto es un poco antiguo, pero para las versiones más recientes de Gradle, donde NO hay directorio src / test / resources, pero solo un directorio de recursos para todo el proyecto, debes agregar esta línea a tu archivo Gradle.

android {
   testOptions {
      unitTests {
         includeAndroidResources = true
      }
    }
}

Al hacer esto, puede acceder a su recurso con:

 this.getClass().getClassLoader().getResourceAsStream(fileName);

He estado buscando esto y no pude encontrar una respuesta, así que decidí ayudar a otros aquí.

Raphael Ayres
fuente
1

En realidad, esto es lo que me funcionó con las pruebas de instrumentación (ejecución de Android Studio versión 3.5.3 , Android Gradle Plugin versión 3.5.3 , Gradle versión 6.0.1 ):

  1. Pon tus archivos en src/androidTest/assetscarpeta
  2. En su archivo de prueba:

InputStream is = InstrumentationRegistry.getInstrumentation().getContext().getAssets().open("filename.txt");

Michele
fuente