Test dell'unità Android Studio: leggere il file di dati (input)


96

In uno unit test, come posso leggere i dati da un file json sul mio file system (desktop), senza codificare il percorso?

Vorrei leggere l'input di prova (per i miei metodi di analisi) da un file invece di creare stringhe statiche.

Il file si trova nella stessa posizione del mio codice di unit test, ma posso anche posizionarlo da qualche altra parte nel progetto, se necessario. Sto usando Android Studio.


3
Ho provato quasi tutte le combinazioni con IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8"), restituisce sempre null. Probabilmente perché i file non verranno inclusi nel jar.
Frank

Stiamo parlando di unit test che coinvolgono un emulatore / dispositivo Android?
AndroidEx

@ Android777 Penso che stiamo parlando del nuovo supporto per unit test introdotto nella recente versione di Android Studio tools.android.com/tech-docs/unit-testing-support
akhy

@Frank dove metti test_documents.json? directory delle risorse?
akhy

Sì, stiamo parlando del nuovo supporto per i test unitari, non coinvolgendo l'emulatore / dispositivo. Non l'ho inserito nella directory assets, perché poi viene impacchettato con l'apk live. L'ho inserito nella stessa cartella dei file di prova (java).
Frank

Risposte:


149

A seconda della android-gradle-pluginversione:

1. versione 1.5 e successive:

Basta inserire il file json src/test/resources/test.jsone referenziarlo come

classLoader.getResource("test.json"). 

Non è necessaria alcuna modifica graduale.

2. versione precedente alla 1.5 : (o se per qualche motivo la soluzione sopra non funziona)

  1. Assicurati di utilizzare almeno Android Gradle Plugin versione 1.1 . Segui il link per configurare correttamente Android Studio.

  2. Crea testdirectory. Metti le classi di unit test nella javadirectory e metti il ​​tuo file di risorse nella resdirectory. Android Studio dovrebbe contrassegnarli come segue:

    inserisci qui la descrizione dell'immagine

  3. Crea gradleattività per copiare le risorse nella directory delle classi per renderle visibili per classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
    
  4. Ora puoi utilizzare questo metodo per ottenere il Fileriferimento per la risorsa file:

    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. Esegui un test unitario con Ctrl+ Shift+ F10su tutta la classe o su un metodo di test specifico.

1
Eccezionale! La tua modifica, senza test strumentali, funziona a meraviglia, grazie!
Frank

4
È una bella soluzione, ma non sempre funziona. Se esegui, esegui l'operazione di pulizia e quindi esegui testDebug, l'operazione non riesce. Fondamentalmente lo sviluppatore deve sapere che deve eseguire l'attività assembleDebug prima di testDebug. Avete qualche suggerimento per migliorare questo?
joaoprudencio

18
Con AndroidStudio 1.5 con il plugin Android 1.5.0 posiziona il tuo file json qui src/test/resources/test.jsone fai riferimento ad esso come classLoader.getResource("test.json"). Non è necessaria alcuna modifica graduale. Anche le cartelle nidificate all'interno resourcesfunzionano.
Sergii Pechenizkyi

6
Risposta incompleta. Che cos'è classLoader? dove posizionare questa riga di codice? cosa puoi fare con il risultato di ritorno ?. Fornisci un codice più completo. -1
voghDev

3
Da leggere ./src/test/resources/file.txtin Kotlin:TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik

76

Per i test di unità locali (rispetto ai test di strumentazione), puoi inserire file src/test/resourcese leggerli utilizzando classLoader. Ad esempio, il codice seguente apre il myFile.txtfile nella directory delle risorse.

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

Ha funzionato con

  • Android Studio 1.5.1
  • plugin gradle 1.3.1

Questo non funziona per me, per favore leggi la mia domanda qui stackoverflow.com/questions/36295824/…
Tyler Pfaff

5
Questo ha funzionato per me, quando sono passato da "src / test / res" a "src / test / resources". Utilizzando Android Studio 2.0 RC 3, gradle: 2.0.0-rc3
Alex Bravo

ha funzionato come previsto. Ma il test viene superato anche se il file non è disponibile in "src / test / resources /" ad esempio: "rules.xml", ma InputStream risulta nullo in questo caso.
anand krish

4
kotlin:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj.

Ha funzionato come un fascino!
Amit Bhandari

15

Nel mio caso, la soluzione era aggiungere al file gradle

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

Dopo di che tutto è stato trovato da AS 2.3.1

javaClass.classLoader.getResourceAsStream("countries.txt")

Ho fatto qualcosa di molto simile (Kotlin): 1. crea una cartella e un file in: root/app/src/test/resources/test.json 2. leggi i dati in questo modo:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj.

8

Ho avuto molti problemi con le risorse di test in Android Studio, quindi ho impostato alcuni test per maggiore chiarezza. Nel mio progetto mobile(Applicazione Android) ho aggiunto i seguenti file:

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

La classe di test (tutti i test vengono superati):

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"));

Nello stesso progetto radice ho un progetto Java (non Android) chiamato data. Se aggiungo gli stessi file al progetto dati:

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

Quindi tutti i test precedenti falliranno se li eseguo da Android Studio, ma passano sulla riga di comando con ./gradlew data:test. Per aggirare il problema uso questo hack (in 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"))
}

Utilizzo: resource('/test.txt')

Android Studio 2.3, Gradle 3.3


Ottima risposta (dopo 45 minuti di ricerca 😌). Entra nel vivo di diversi problemi e semplifica la replica dei risultati utilizzando i test stessi. Fwiw, In AS 2.3.1, Gradle 2.3.1, le getClassLoader()versioni funzionano come previsto. Cioè trovano i file, entrambi eseguiti da Android Studio E dalla riga di comando sulla mia macchina macOS e sul server CI Linux (CircleCI). Quindi vado con quello e spero che Gradle 3.3 non lo rompa più tardi ...
mm2001

Bello! Sto riscontrando lo stesso problema di caricamento delle risorse qui. AS 2.3.2, Gradle 3.3. I test funzionano dalla riga di comando ma non tramite AS, poiché build/resources/testnon sono inclusi nel classpath interattivo.
Mark McKenna

6

Se vai su Esegui -> Modifica configurazioni -> JUnit e quindi selezioni la configurazione di esecuzione per i tuoi test unitari, c'è un'impostazione "Directory di lavoro". Questo dovrebbe indicare dovunque sia il tuo file json. Tieni presente che questo potrebbe rompere altri test.


e che usare this.getClass (). getResourceAsStream (test.json)? Ho aggiunto i file lì, nella radice del progetto, ancora non trova i file.
Frank

Può essere usato per caricare file usando new File()o simili, ma non funziona direttamente con il metodo di caricamento del percorso di classe descritto sopra. È anche un po 'complicato perché ogni nuova configurazione di esecuzione deve impostare la directory di lavoro e, per impostazione predefinita, la riga di comando AS e Gradle preferisce utilizzare diverse directory di lavoro ... che dolore
Mark McKenna

4

Ho pensato di aggiungere qui le mie scoperte. So che questo è un po 'vecchio ma per le versioni più recenti di Gradle, dove NON c'è la directory src / test / resources, ma solo una singola directory delle risorse per l'intero progetto, devi aggiungere questa riga al tuo file Gradle.

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

In questo modo puoi accedere alla tua risorsa con:

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

Ho cercato questo e non sono riuscito a trovare una risposta, quindi ho deciso di aiutare gli altri qui.


1

In realtà, questo è ciò che ha funzionato per me con i test di strumentazione (con Android Studio versione 3.5.3 , Android Gradle Plugin versione 3.5.3 , Gradle versione 6.0.1 ):

  1. Metti i tuoi file nella src/androidTest/assetscartella
  2. Nel tuo file di prova:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.