Android Studio-Komponententest: Daten (Eingabe) lesen


96

Wie kann ich in einem Komponententest Daten aus einer JSON-Datei auf meinem (Desktop-) Dateisystem lesen, ohne den Pfad fest zu codieren?

Ich möchte Testeingaben (für meine Parsing-Methoden) aus einer Datei lesen, anstatt statische Strings zu erstellen.

Die Datei befindet sich am selben Speicherort wie mein Unit-Test-Code, kann aber bei Bedarf auch an einer anderen Stelle im Projekt abgelegt werden. Ich benutze Android Studio.


3
Ich habe fast jede Kombination mit IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8") ausprobiert. Es wird immer null zurückgegeben. Wahrscheinlich, weil die Dateien nicht in das Glas aufgenommen werden.
Frank

Sprechen wir über Unit-Tests mit Android-Emulator / Gerät?
AndroidEx

@ Android777 Ich denke, wir sprechen über neue Unit-Test-Unterstützung in der neuesten Version von Android Studio tools.android.com/tech-docs/unit-testing-support
akhy

@Frank wo platzierst du test_documents.json? Vermögensverzeichnis?
Akhy

Ja, wir sprechen über die neue Unterstützung für Komponententests, ohne den Emulator / das Gerät. Ich habe es nicht in das Assets-Verzeichnis gestellt, weil es dann mit der Live-Apk verpackt wird. Ich habe es in den gleichen Ordner wie die Testdateien (Java) gelegt.
Frank

Antworten:


149

Je nach android-gradle-pluginVersion:

1. Version 1.5 und höher:

Legen Sie einfach die json-Datei auf src/test/resources/test.jsonund verweisen Sie darauf als

classLoader.getResource("test.json"). 

Es ist keine Gradle-Modifikation erforderlich.

2. Version unter 1.5 : (oder wenn aus irgendeinem Grund die oben genannte Lösung nicht funktioniert)

  1. Stellen Sie sicher, dass Sie mindestens Android Gradle Plugin Version 1.1 verwenden . Folgen Sie dem Link, um Android Studio korrekt einzurichten.

  2. testVerzeichnis erstellen . Legen Sie Unit-Test-Klassen im javaVerzeichnis ab und legen Sie Ihre Ressourcendatei im resVerzeichnis ab. Android Studio sollte sie wie folgt markieren:

    Geben Sie hier die Bildbeschreibung ein

  3. Erstellen Sie eine gradleAufgabe, um Ressourcen in das Klassenverzeichnis zu kopieren und sie sichtbar zu machen für classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
  4. Jetzt können Sie diese Methode verwenden, um eine FileReferenz für die Dateiressource abzurufen:

    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. Führen Sie den Komponententest mit Ctrl+ Shift+ F10für die gesamte Klasse oder die spezifische Testmethode durch.

1
Genial! Ihre Bearbeitung ohne Instrumententests funktioniert wie ein Zauber, danke!
Frank

4
Es ist eine schöne Lösung, aber es funktioniert nicht immer. Wenn Sie die Bereinigungstask ausführen und dann testDebug ausführen, schlägt dies fehl. Grundsätzlich muss der Entwickler wissen, dass er die Aufgabe assembleDebug vor testDebug ausführen muss. Habt ihr einen Vorschlag, dies zu verbessern?
Joaoprudencio

18
Mit AndroidStudio 1.5 mit Android Plugin 1.5.0 platzieren Sie Ihre JSON-Datei hier src/test/resources/test.jsonund verweisen Sie darauf als classLoader.getResource("test.json"). Es ist keine Gradle-Modifikation erforderlich. Verschachtelte Ordner im Inneren resourcesfunktionieren ebenfalls.
Sergii Pechenizkyi

6
Unvollständige Antwort. Was ist classLoader? Wo soll diese Codezeile platziert werden? Was können Sie mit dem Rückgabeergebnis tun? Bitte geben Sie einen vollständigeren Code an. -1
voghDev

3
In ./src/test/resources/file.txtKotlin zu lesen :TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik

76

Bei lokalen src/test/resourcesKomponententests (im Vergleich zu Instrumentierungstests) können Sie Dateien ablegen und mit classLoader lesen. Der folgende Code öffnet beispielsweise die myFile.txtDatei im Ressourcenverzeichnis.

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

Es hat funktioniert mit

  • Android Studio 1.5.1
  • Gradle Plugin 1.3.1

Dies funktioniert nicht für mich, bitte sehen Sie meine Frage hier stackoverflow.com/questions/36295824/…
Tyler Pfaff

5
Dies funktionierte für mich, als ich von "src / test / res" zu "src / test / resources" wechselte. Mit Android Studio 2.0 RC 3, Gradle: 2.0.0-rc3
Alex Bravo

arbeitete wie erwartet. Der Test wird jedoch bestanden, auch wenn die Datei unter "src / test / resources /" nicht verfügbar ist, z. B.: "Rules.xml". In diesem Fall ist InputStream jedoch null.
Anand Krishna

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

Arbeitete wie Charme!
Amit Bhandari

15

In meinem Fall bestand die Lösung darin, der Gradle-Datei etwas hinzuzufügen

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

Danach wurde alles von AS 2.3.1 gefunden

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

Ich habe etwas sehr ähnliches gemacht (Kotlin): 1. Ordner und Datei erstellen unter: root/app/src/test/resources/test.json 2. Daten wie val jsonFile = ClassLoader.getSystemResource("test.json").readText()
folgt

8

Ich hatte viele Probleme mit Testressourcen in Android Studio, daher habe ich aus Gründen der Übersichtlichkeit einige Tests eingerichtet. In meinem mobileProjekt (Android-Anwendung) habe ich folgende Dateien hinzugefügt:

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

Die Testklasse (alle Tests bestehen):

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

Im selben Root-Projekt habe ich ein Java-Projekt (nicht Android) namens data. Wenn ich dem Datenprojekt dieselben Dateien hinzufüge:

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

Dann schlagen alle oben genannten Tests fehl, wenn ich sie von Android Studio aus ausführe, aber sie übergeben die Befehlszeile mit ./gradlew data:test. Um das zu umgehen, benutze ich diesen 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"))
}

Verwendung: resource('/test.txt')

Android Studio 2.3, Gradle 3.3


Tolle Antwort (nach 45 Minuten Suche 😌). Es bringt mehrere Probleme auf den Punkt und macht es einfach, die Ergebnisse mithilfe der Tests selbst zu replizieren. Fwiw, In AS 2.3.1, Gradle 2.3.1 getClassLoader()funktionieren die Versionen wie erwartet. Das heißt, sie finden die Dateien, die beide von Android Studio UND über die Befehlszeile auf meinem MacOS-Computer und auf dem Linux CI-Server (CircleCI) ausgeführt werden. Also mache ich damit weiter und hoffe, dass Gradle 3.3 es später nicht kaputt macht ...
mm2001

Nett! Ich sehe hier das gleiche Problem beim Laden von Ressourcen. AS 2.3.2, Gradle 3.3. Die Tests funktionieren über die Befehlszeile, jedoch nicht über AS, da sie build/resources/testnicht im interaktiven Klassenpfad enthalten sind.
Mark McKenna

6

Wenn Sie zu Ausführen -> Konfigurationen bearbeiten -> JUnit gehen und dann die Ausführungskonfiguration für Ihre Komponententests auswählen, gibt es die Einstellung "Arbeitsverzeichnis". Das sollte zeigen, wo sich Ihre JSON-Datei befindet. Beachten Sie, dass dies andere Tests beschädigen kann.


und dann this.getClass () verwenden. getResourceAsStream (test.json)? Ich habe die Dateien dort hinzugefügt, im Stammverzeichnis des Projekts werden die Dateien immer noch nicht gefunden.
Frank

Dies kann zum Laden von Dateien mit new File()oder ähnlich verwendet werden, funktioniert jedoch nicht direkt mit der oben beschriebenen Methode zum Laden von Klassenpfaden. Es ist auch ein bisschen knifflig, weil jede neue Laufkonfiguration das Arbeitsverzeichnis festlegen muss und standardmäßig AS- und Gradle-Befehlszeilen unterschiedliche Arbeitsverzeichnisse verwenden ... so ein Schmerz
Mark McKenna

4

Ich denke, ich sollte meine Erkenntnisse hier hinzufügen. Ich weiß, dass dies etwas alt ist, aber für die neueren Versionen von Gradle, in denen es KEIN Verzeichnis src / test / resources gibt, sondern nur ein einziges Ressourcenverzeichnis für das gesamte Projekt, müssen Sie diese Zeile zu Ihrer Gradle-Datei hinzufügen.

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

Auf diese Weise können Sie auf Ihre Ressource zugreifen mit:

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

Ich habe danach gesucht und konnte keine Antwort finden, deshalb habe ich beschlossen, anderen hier zu helfen.


1

Das hat bei Instrumentationstests (Ausführen von Android Studio Version 3.5.3 , Android Gradle Plugin Version 3.5.3 , Gradle Version 6.0.1 ) für mich funktioniert :

  1. Legen Sie Ihre Dateien in einen src/androidTest/assetsOrdner
  2. In Ihrer Testdatei:

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.