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.

Frank
quelle
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.
klimat
quelle
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
user3113045
quelle
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")
ar-g
quelle
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

Liebe
quelle
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.

Tas Morf
quelle
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.

Raphael Ayres
quelle
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");

Michele
quelle