Pengujian unit Android Studio: membaca file data (input)

96

Dalam pengujian unit, bagaimana cara membaca data dari file json di sistem file (desktop) saya, tanpa hardcode jalur?

Saya ingin membaca input pengujian (untuk metode penguraian saya) dari file alih-alih membuat String statis.

File tersebut berada di lokasi yang sama dengan kode pengujian unit saya, tetapi saya juga dapat meletakkannya di tempat lain dalam proyek jika diperlukan. Saya menggunakan Android Studio.

jujur
sumber
3
Saya mencoba hampir setiap kombinasi dengan IOUtils.toString (this.getClass (). GetResourceAsStream ("test_documents.json"), "UTF-8"), selalu mengembalikan null. Mungkin karena file tidak akan dimasukkan ke dalam toples.
Frank
Apakah kita berbicara tentang pengujian unit yang melibatkan emulator / perangkat android?
AndroidEx
@ Android777 Saya rasa kita sedang berbicara tentang dukungan pengujian unit baru yang diperkenalkan dalam versi terbaru dari alat Android Studio.android.com/tech-docs/unit-testing-support
akhy
@ Frank di mana Anda menempatkan test_documents.json? direktori aset?
akhy
Ya, kami berbicara tentang dukungan pengujian unit baru, tidak melibatkan emulator / perangkat. Saya tidak menempatkannya di direktori assets, karena itu akan dikemas dengan apk langsung. Saya meletakkannya di folder yang sama dengan file test (java).
Frank

Jawaban:

149

Tergantung android-gradle-pluginversinya:

1. versi 1.5 dan lebih tinggi:

Letakkan saja file json src/test/resources/test.jsondan rujuk sebagai

classLoader.getResource("test.json"). 

Tidak perlu modifikasi gradle.

2. versi di bawah 1.5 : (atau jika karena alasan tertentu solusi di atas tidak berfungsi)

  1. Pastikan Anda menggunakan setidaknya Android Gradle Plugin versi 1.1 . Ikuti link untuk menyiapkan Android Studio dengan benar.

  2. Buat testdirektori. Letakkan kelas pengujian unit dalam javadirektori dan letakkan file sumber daya Anda di resdirektori. Android Studio harus menandainya seperti berikut:

    masukkan deskripsi gambar di sini

  3. Buat gradletugas untuk menyalin resource ke direktori kelas agar terlihat untuk classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
  4. Sekarang Anda dapat menggunakan metode ini untuk mendapatkan File referensi untuk sumber daya 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. Jalankan pengujian unit dengan Ctrl+ Shift+ F10di seluruh kelas atau metode pengujian spesifik.
klimat
sumber
1
Hebat! Hasil edit Anda, tanpa tes instrumental, bekerja seperti pesona, terima kasih!
Frank
4
Ini solusi yang bagus, tetapi tidak selalu berhasil. Jika Anda menjalankan tugas bersih, kemudian menjalankan testDebug gagal. Pada dasarnya pengembang perlu mengetahui bahwa ia harus menjalankan tugas assembleDebug sebelum testDebug. Apakah kalian punya saran untuk memperbaiki ini?
joaoprudencio
18
Dengan AndroidStudio 1.5 dengan plugin android 1.5.0 tempatkan file json Anda di sini src/test/resources/test.jsondan referensikan sebagai classLoader.getResource("test.json"). Tidak perlu modifikasi gradle. Folder bersarang di dalamnya resourcesjuga berfungsi.
Sergii Pechenizkyi
6
Jawaban tidak lengkap. Apa classLoader? di mana menempatkan baris kode ini? apa yang dapat Anda lakukan dengan hasil pengembalian ?. Harap berikan kode yang lebih lengkap. -1
voghDev
3
Untuk membaca ./src/test/resources/file.txtdi Kotlin:TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik
76

Untuk pengujian unit lokal (vs. pengujian instrumentasi), Anda dapat meletakkan file di bawah src/test/resourcesdan membacanya menggunakan classLoader. Misalnya, kode berikut membuka myFile.txtfile di direktori resource.

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

Ini bekerja dengan

  • Android Studio 1.5.1
  • plugin gradle 1.3.1
pengguna3113045
sumber
Ini tidak berhasil untuk saya, silakan lihat pertanyaan saya di sini stackoverflow.com/questions/36295824/…
Tyler Pfaff
5
Ini berhasil untuk saya, ketika saya mengubah dari "src / test / res" menjadi "src / test / resources". Menggunakan Android Studio 2.0 RC 3, gradle: 2.0.0-rc3
Alex Bravo
bekerja seperti yang diharapkan. Namun pengujian semakin berhasil meskipun file tidak tersedia di bawah "src / test / resources /" misalnya: "rules.xml", tetapi InputStream menghasilkan null dalam kasus ini.
anand krish
4
kotlin:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj.
Bekerja seperti pesona!
Amit Bhandari
15

Dalam kasus saya, solusinya adalah menambahkan ke file gradle

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

Setelah itu semuanya ditemukan oleh AS 2.3.1

javaClass.classLoader.getResourceAsStream("countries.txt")
ar-g
sumber
1
Saya melakukan sesuatu yang sangat mirip (Kotlin): 1. membuat folder dan file di: root/app/src/test/resources/test.json 2. membaca data seperti ini:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj.
8

Saya mengalami banyak masalah dengan sumber daya pengujian di Android Studio, jadi saya menyiapkan beberapa pengujian untuk kejelasan. Dalam mobileproyek (Aplikasi Android) saya, saya menambahkan file berikut:

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

Kelas pengujian (semua pengujian berhasil):

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

Dalam proyek root yang sama saya memiliki proyek Java (bukan Android) yang disebut data. Jika saya menambahkan file yang sama ke proyek data:

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

Maka semua pengujian di atas akan gagal jika saya mengeksekusinya dari Android Studio, tetapi meneruskan pada baris perintah dengan ./gradlew data:test. Untuk menyiasatinya saya menggunakan hack ini (di 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"))
}

Pemakaian: resource('/test.txt')

Android Studio 2.3, Gradle 3.3

Cinta
sumber
Jawaban bagus (setelah 45 menit mencari 😌). Ini menyentuh inti dari beberapa masalah dan membuatnya mudah untuk mereplikasi hasil menggunakan tes itu sendiri. Fwiw, Di AS 2.3.1, Gradle 2.3.1, getClassLoader()versi berfungsi seperti yang diharapkan. Yaitu mereka menemukan file, keduanya dijalankan dari Android Studio DAN dari baris perintah di mesin macOS saya, dan di server Linux CI (CircleCI). Jadi saya akan melakukannya dan berharap Gradle 3.3 tidak merusaknya nanti ...
mm2001
Bagus! Saya melihat masalah pemuatan sumber daya yang sama di sini. AS 2.3.2, Gradle 3.3. Pengujian bekerja dari baris perintah tetapi tidak melalui AS, karena build/resources/testtidak disertakan dalam jalur kelas interaktif.
Mark McKenna
6

Jika Anda pergi ke Jalankan -> Edit konfigurasi -> JUnit dan kemudian pilih konfigurasi jalankan untuk pengujian unit Anda, terdapat pengaturan 'Direktori kerja'. Itu harus menunjuk ke mana pun file json Anda. Ingatlah bahwa ini mungkin merusak tes lainnya.

Tas Morf
sumber
dan kemudian gunakan this.getClass (). getResourceAsStream (test.json)? Saya menambahkan file di sana, di root proyek, masih tidak menemukan file.
Frank
Ini dapat digunakan untuk memuat file menggunakan new File()atau serupa, tetapi tidak bekerja secara langsung dengan metode pemuatan classpath yang dijelaskan di atas. Ini juga sedikit rumit karena setiap konfigurasi yang baru dijalankan perlu menyetel dir yang berfungsi, dan secara default baris perintah AS dan Gradle suka menggunakan direktori kerja yang berbeda ... sungguh merepotkan
Mark McKenna
5

Saya pikir saya harus menambahkan temuan saya di sini. Saya tahu ini agak lama tetapi untuk versi Gradle yang lebih baru, di mana TIDAK ada direktori src / test / resources, tetapi hanya satu direktori resource untuk keseluruhan proyek, Anda harus menambahkan baris ini ke file Gradle Anda.

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

Dengan melakukan ini, Anda dapat mengakses sumber daya Anda dengan:

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

Saya telah mencari ini dan tidak dapat menemukan jawaban, jadi saya memutuskan untuk membantu orang lain di sini.

Raphael Ayres
sumber
2

Sebenarnya, inilah yang berhasil untuk saya dengan Uji Instrumentasi (Menjalankan Android Studio versi 3.5.3 , Plugin Android Gradle versi 3.5.3 , Gradle versi 6.0.1 ):

  1. Taruh file Anda di src/androidTest/assetsfolder
  2. Di file pengujian Anda:

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

Michele
sumber