Testy jednostkowe Android Studio: odczyt pliku danych (wejściowych)

96

W teście jednostkowym, jak mogę odczytać dane z pliku JSON w moim (stacjonarnym) systemie plików bez zakodowania ścieżki na stałe?

Chciałbym czytać testowe dane wejściowe (dla moich metod analizy) z pliku zamiast tworzyć statyczne ciągi znaków.

Plik znajduje się w tej samej lokalizacji, co mój kod testów jednostkowych, ale w razie potrzeby mogę go również umieścić w innym miejscu projektu. Używam Android Studio.

Szczery
źródło
3
Próbowałem prawie każdej kombinacji z IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8"), zawsze zwraca wartość null. Prawdopodobnie dlatego, że pliki nie zostaną dołączone do jar.
Frank
Czy mówimy o testach jednostkowych dotyczących emulatora / urządzenia z systemem Android?
AndroidEx
@ Android777 Myślę, że mówimy o nowej obsłudze testów jednostkowych wprowadzonej w najnowszej wersji Android Studio tools.android.com/tech-docs/unit-testing-support
akhy
@Frank gdzie stawiasz test_documents.json? katalog zasobów?
akhy
Tak, mówimy o nowej obsłudze testów jednostkowych, bez udziału emulatora / urządzenia. Nie umieściłem go w katalogu aktywów, ponieważ wtedy jest pakowany z apk na żywo. Umieściłem go w tym samym folderze, co pliki testowe (java).
Frank,

Odpowiedzi:

149

W zależności od android-gradle-pluginwersji:

1. wersja 1.5 i nowsze:

Po prostu umieść plik json src/test/resources/test.jsoni określ go jako

classLoader.getResource("test.json"). 

Nie jest wymagana modyfikacja gradientu.

2. wersja poniżej 1.5 : (lub jeśli z jakiegoś powodu powyższe rozwiązanie nie działa)

  1. Upewnij się, że używasz co najmniej wtyczki Android Gradle w wersji 1.1 . Kliknij łącze, aby poprawnie skonfigurować Android Studio.

  2. Utwórz testkatalog. Umieść klasy testów jednostkowych w javakatalogu i umieść plik zasobów w reskatalogu. Android Studio powinno je oznaczyć następująco:

    wprowadź opis obrazu tutaj

  3. Utwórz gradlezadanie kopiowania zasobów do katalogu zajęć, aby były widoczne dla classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
  4. Teraz możesz użyć tej metody, aby uzyskać Fileodniesienie do zasobu plikowego:

    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. Uruchom test jednostkowy przez Ctrl+ Shift+ F10na całej klasie lub określonej metodzie testowej.
klimat
źródło
1
Niesamowite! Twoja edycja bez testowania instrumentów działa jak urok, dzięki!
Frank,
4
To fajne rozwiązanie, ale nie zawsze działa. Jeśli wykonasz zadanie czyszczenia, a następnie uruchomisz testDebug, nie powiedzie się. Zasadniczo programista musi wiedzieć, że musi uruchomić zadanie assembleDebug przed testDebug. Czy macie jakieś sugestie, jak to poprawić?
joaoprudencio
18
W AndroidStudio 1.5 z wtyczką dla Androida 1.5.0 umieść tutaj swój plik json src/test/resources/test.jsoni odwołaj się do niego jako classLoader.getResource("test.json"). Nie jest wymagana modyfikacja gradacji. resourcesDziałają również zagnieżdżone foldery wewnątrz .
Sergii Pechenizkyi
6
Niekompletna odpowiedź. Co to jest classLoader? gdzie umieścić ten wiersz kodu? co możesz zrobić z wynikiem zwrotu ?. Podaj pełniejszy kod. -1
voghDev
3
Do przeczytania ./src/test/resources/file.txtw Kotlinie:TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik
76

W przypadku lokalnych testów jednostkowych (w porównaniu z testami instrumentacji) można umieścić pliki pod src/test/resourcesi odczytać je za pomocą classLoader. Na przykład poniższy kod otwiera myFile.txtplik w katalogu zasobów.

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

To działało

  • Android Studio 1.5.1
  • wtyczka gradle 1.3.1
user3113045
źródło
To nie działa dla mnie, zobacz moje pytanie tutaj stackoverflow.com/questions/36295824/…
Tyler Pfaff
5
U mnie to zadziałało, kiedy zmieniłem z „src / test / res” na „src / test / resources”. Używając Android Studio 2.0 RC 3, gradle: 2.0.0-rc3
Alex Bravo
działał zgodnie z oczekiwaniami. Ale test kończy się pomyślnie, nawet jeśli plik nie jest dostępny w „src / test / resources /”, np .: „rules.xml”, ale w tym przypadku wynik InputStream jest pusty.
anand krish
4
kotlin:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj.
Działało jak urok!
Amit Bhandari
15

W moim przypadku rozwiązaniem było dodanie do pliku gradle

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

Po tym wszystko zostało znalezione przez AS 2.3.1

javaClass.classLoader.getResourceAsStream("countries.txt")
ar-g
źródło
1
Zrobiłem coś bardzo podobnego (Kotlin): 1. utwórz folder i plik pod adresem: root/app/src/test/resources/test.json 2. przeczytaj dane w ten sposób:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj.
8

Miałem wiele problemów z zasobami testowymi w Android Studio, więc skonfigurowałem kilka testów dla przejrzystości. W moim mobileprojekcie (Android Application) dodałem następujące pliki:

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

Klasa testu (wszystkie testy zdały):

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

W tym samym projekcie głównym mam projekt Java (nie Android) o nazwie data. Jeśli dodam te same pliki do projektu danych:

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

Wtedy wszystkie powyższe testy zakończą się niepowodzeniem, jeśli wykonam je z Android Studio, ale przekażą je w wierszu poleceń z ./gradlew data:test. Aby to obejść, używam tego hacka (w 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"))
}

Stosowanie: resource('/test.txt')

Android Studio 2.3, Gradle 3.3

Miłość
źródło
Świetna odpowiedź (po 45 minutach wyszukiwania 😌). Dochodzi do sedna kilku problemów i ułatwia powtórzenie wyników przy użyciu samych testów. Fwiw, W AS 2.3.1, Gradle 2.3.1, getClassLoader()wersje działają zgodnie z oczekiwaniami. To znaczy, że znajdują pliki, oba uruchamiane z Android Studio ORAZ z wiersza poleceń na moim komputerze z systemem macOS i na serwerze Linux CI (CircleCI). Więc idę z tym i mam nadzieję, że Gradle 3.3 nie
zepsuje
Miły! Widzę tutaj ten sam problem z ładowaniem zasobów. AS 2.3.2, Gradle 3.3. Testy działają z wiersza poleceń, ale nie przez AS, ponieważ build/resources/testnie są uwzględnione w interaktywnej ścieżce klas.
Mark McKenna
6

Jeśli przejdziesz do Uruchom -> Edytuj konfiguracje -> JUnit, a następnie wybierzesz konfigurację uruchamiania dla testów jednostkowych, pojawi się ustawienie „Katalog roboczy”. To powinno wskazywać na to, gdzie jest twój plik json. Pamiętaj, że może to zepsuć inne testy.

Tas Morf
źródło
a następnie użyj this.getClass (). getResourceAsStream (test.json)? Dodałem pliki tam, w katalogu głównym projektu, nadal nie znajduje plików.
Frank,
Można tego użyć do ładowania plików przy użyciu new File()lub podobnego, ale nie działa bezpośrednio z metodą ładowania ścieżki klas opisaną powyżej. Jest to również trochę skomplikowane, ponieważ każda nowa konfiguracja uruchamiania musi ustawić katalog roboczy, a domyślnie linie poleceń AS i Gradle lubią używać różnych roboczych katalogów ... taki ból
Mark McKenna
5

Pomyślałem, że powinienem tutaj dodać swoje ustalenia. Wiem, że jest to trochę stare, ale w nowszych wersjach Gradle, w których NIE ma katalogu src / test / resources, ale tylko jeden katalog zasobów dla całego projektu, musisz dodać tę linię do pliku Gradle.

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

W ten sposób możesz uzyskać dostęp do swojego zasobu za pomocą:

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

Szukałem tego i nie mogłem znaleźć odpowiedzi, więc postanowiłem pomóc innym tutaj.

Raphael Ayres
źródło
1

Właściwie to zadziałało dla mnie z testami instrumentacji (działa Android Studio w wersji 3.5.3 , wtyczka Android Gradle w wersji 3.5.3 , Gradle w wersji 6.0.1 ):

  1. Umieść swoje pliki w src/androidTest/assetsfolderze
  2. W pliku testowym:

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

Michele
źródło