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.


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.

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

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

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


Ś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.


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.


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.