Dasar-dasar Pengujian

Pengguna berinteraksi dengan aplikasi Anda di berbagai level, mulai dari menekan tombol hingga mendownload informasi ke perangkat mereka. Oleh karena itu, Anda harus menguji berbagai kasus penggunaan dan interaksi saat Anda mengembangkan aplikasi Anda secara iteratif.

Mengatur kode untuk pengujian

Saat aplikasi Anda berkembang, Anda mungkin perlu mengambil data dari server, berinteraksi dengan sensor perangkat, mengakses penyimpanan lokal, atau merender antarmuka pengguna yang kompleks. Fleksibilitas aplikasi Anda membutuhkan strategi pengujian yang komprehensif.

Membuat dan menguji kode secara iteratif

Saat mengembangkan fitur secara iteratif, mulailah dengan menulis pengujian baru atau dengan menambahkan kasus dan pernyataan ke pengujian unit yang ada. Pada awalnya pengujian gagal karena fitur tersebut belum diimplementasikan.

Penting untuk mempertimbangkan unit tanggung jawab yang muncul saat Anda merancang fitur baru. Untuk setiap unit, Anda menulis pengujian unit yang sesuai. Pengujian unit Anda mungkin hampir memakai semua interaksi yang mungkin terjadi dengan unit, termasuk interaksi standar, input yang tidak valid, dan kasus di mana resource tidak tersedia. Manfaatkan library Jetpack jika memungkinkan; saat Anda menggunakan library yang teruji dengan baik ini, Anda dapat berfokus pada memvalidasi perilaku tertentu untuk aplikasi Anda.

Siklus pengembangan pengujian terdiri dari penulisan unit uji yang gagal, penulisan kode agar unit tersebut lulus pengujian, lalu pemfaktoran ulang. Seluruh siklus pengembangan fitur ada di dalam satu langkah siklus berbasis UI yang lebih besar.
Gambar 1. Dua siklus yang berkaitan dengan pengembangan iteratif berbasis pengujian

Alur kerja penuh, seperti yang ditunjukkan pada Gambar 1, berisi serangkaian siklus berulang dan tersarang di mana siklus panjang, lambat, berbasis UI menguji integrasi unit kode. Uji unit itu sendiri menggunakan siklus pengembangan yang lebih ringkas dan lebih cepat. Serangkaian siklus ini berlanjut hingga aplikasi Anda memenuhi setiap kasus penggunaan.

Menampilkan aplikasi sebagai serangkaian modul

Untuk menjadikan kode lebih mudah diuji, kembangkan kode Anda dalam bentuk modul, di mana setiap modul merepresentasikan tugas tertentu yang diselesaikan pengguna dalam aplikasi Anda. Perspektif ini berbeda dengan tampilan berbasis tumpukan yang biasanya berisi lapisan yang merepresentasikan UI, logika bisnis, dan data.

Misalnya, aplikasi "daftar tugas" mungkin memiliki modul untuk membuat tugas, melihat statistik tentang tugas yang telah diselesaikan, dan mengambil foto untuk dikaitkan dengan tugas tertentu. Arsitektur modular tersebut juga membantu Anda membuat class yang tidak terkait tetap terpisah dan menyediakan struktur alami untuk menetapkan kepemilikan dalam tim pengembangan Anda.

Penting untuk menetapkan batas yang ditentukan dengan baik di setiap modul, dan untuk membuat modul baru saat skala dan kompleksitas aplikasi Anda berkembang. Setiap modul harus berfokus pada satu saja, dan API yang memungkinkan komunikasi antar-modul harus konsisten. Untuk memudahkan dan mempercepat pengujian interaksi antar-modul ini, pertimbangkan untuk membuat implementasi palsu dari modul Anda. Dalam pengujian Anda, implementasi asli dari suatu modul dapat memanggil implementasi palsu dari modul lainnya.

Namun, saat membuat modul baru, jangan terlalu dogmatis sampai membuatnya menjadi fitur yang lengkap dengan seketika. Modul tertentu boleh untuk tidak memiliki satu atau beberapa lapisan tumpukan aplikasi.

Untuk mempelajari lebih lanjut cara menentukan modul di aplikasi, serta dukungan platform untuk membuat dan memublikasikan modul, lihat Android App Bundle.

Mengonfigurasi lingkungan pengujian Anda

Saat menyiapkan lingkungan dan dependensi untuk membuat pengujian di aplikasi Anda, ikuti praktik terbaik yang dijelaskan di bagian ini.

Mengatur direktori pengujian berdasarkan lingkungan eksekusi

Project standar di Android Studio berisi dua direktori tempat Anda melakukan pengujian. Atur pengujian Anda sebagai berikut:

  • Direktori androidTest harus berisi pengujian yang berjalan di perangkat nyata atau virtual. Pengujian ini mencakup pengujian integrasi, pengujian end-to-end, dan pengujian lain di mana JVM sendiri tidak dapat memvalidasi fungsionalitas aplikasi Anda.
  • Direktori test harus berisi pengujian yang berjalan di mesin lokal Anda, seperti pengujian unit.

Mempertimbangkan hasil dari menjalankan pengujian pada berbagai jenis perangkat

Saat menjalankan pengujian pada perangkat, Anda dapat memilih di antara jenis berikut:

  • Perangkat nyata
  • Perangkat virtual (seperti emulator di Android Studio)
  • Perangkat simulasi (seperti Robolectric)

Perangkat nyata menawarkan fidelitas lebih tinggi tetapi juga menghabiskan waktu paling banyak untuk menjalankan pengujian Anda. Di sisi lain, perangkat simulasi, memberikan kecepatan pengujian yang ditingkatkan dengan biaya fidelitas yang lebih rendah. Namun, peningkatan platform dalam resource biner dan looper yang realistis memungkinkan perangkat yang disimulasikan menghasilkan hasil yang lebih realistis.

Perangkat virtual menawarkan keseimbangan antara fidelitas dan kecepatan. Saat Anda menggunakan perangkat virtual untuk menguji, gunakan snapshot untuk meminimalkan waktu persiapan antar-pengujian.

Mempertimbangkan apakah akan menggunakan duplikat pengujian

Saat membuat pengujian, Anda memiliki opsi untuk membuat objek asli atau duplikat pengujian, seperti objek palsu atau objek tiruan. Umumnya, menggunakan objek asli dalam pengujian lebih baik daripada menggunakan duplikat pengujian, terutama saat objek yang diuji memenuhi salah satu kondisi berikut:

  • Objek merupakan objek data.
  • Objek tidak dapat berfungsi kecuali jika berkomunikasi dengan versi objek asli dependensi. Contoh yang bagus adalah peristiwa handler callback.
  • Sulit untuk mereplikasi komunikasi objek dengan dependensi. Contoh yang bagus adalah handler database SQL, di mana database di dalam memori memberikan pengujian yang lebih kuat daripada hasil database objek palsu.

Secara khusus, memalsukan instance jenis yang tidak Anda miliki biasanya akan menghasilkan pengujian rapuh yang hanya berfungsi saat Anda telah memahami kompleksitas penerapan orang lain dari jenis itu. Hanya gunakan objek palsu tersebut sebagai upaya terakhir saja. Anda boleh memalsukan objek Anda sendiri, tetapi ingat bahwa objek palsu yang dianotasi menggunakan @Spy memberikan lebih banyak fidelitas daripada objek palsu yang menonaktifkan semua fungsionalitas dalam class.

Namun, alangkah baiknya untuk membuat objek palsu atau bahkan tiruan jika pengujian Anda mencoba menjalankan jenis operasi berikut pada objek asli:

  • Operasi panjang, seperti memproses file besar.
  • Tindakan non-hermetic, seperti menghubungkan ke port terbuka arbitrer.
  • Konfigurasi yang sulit dibuat.

Tips: Periksa penulis library untuk mengetahui apakah mereka menyediakan infrastruktur pengujian yang didukung secara resmi, seperti objek palsu, yang dapat diandalkan.

Menulis pengujian Anda

Setelah mengonfigurasi lingkungan pengujian Anda, saatnya menulis pengujian yang mengevaluasi fungsionalitas aplikasi Anda. Bagian ini menjelaskan cara menulis pengujian kecil, sedang, dan besar.

Tingkatan Piramida Pengujian

Piramida berisi tiga lapisan
Gambar 2. Piramida Pengujian, menunjukkan tiga kategori pengujian yang harus Anda sertakan dalam paket pengujian aplikasi Anda

Piramida Pengujian, yang ditunjukkan pada Gambar 2, mengilustrasikan bagaimana aplikasi Anda harus menyertakan tiga kategori pengujian: kecil, sedang, dan besar:

  • Pengujian kecil adalah pengujian unit yang memvalidasi perilaku aplikasi Anda, satu class pada satu waktu.
  • Pengujian sedang adalah pengujian integrasi yang memvalidasi interaksi antara level tumpukan dalam modul, atau interaksi antara modul terkait.
  • Pengujian besar adalah pengujian end-to-end yang memvalidasi perjalanan pengguna yang mencakup beberapa modul aplikasi Anda.

Saat Anda membuat piramida, dari pengujian kecil hingga pengujian besar, setiap pengujian tidak hanya meningkat fidelitasnya, tetapi juga meningkat waktu eksekusi dan upaya untuk mengelola dan men-debug. Oleh karena itu, Anda harus menulis lebih banyak pengujian unit daripada pengujian integrasi, dan lebih banyak pengujian integrasi daripada pengujian end-to-end. Meskipun proporsi pengujian untuk setiap kategori dapat bervariasi berdasarkan kasus penggunaan aplikasi Anda, kami biasanya menyarankan pembagian berikut antar-kategori: 70 persen kecil, 20 persen sedang, dan 10 persen besar.

Untuk mempelajari Piramida Pengujian Android lebih lanjut, lihat sesi video Pengembangan Berbasis Pengujian pada Android dari Google I/O 2017, mulai menit 1:51.

Menulis pengujian kecil

Pengujian kecil yang Anda tulis harus merupakan pengujian unit sangat terfokus yang secara menyeluruh memvalidasi fungsionalitas dan kontrak masing-masing class dalam aplikasi Anda.

Saat Anda menambahkan dan mengubah metode dalam class tertentu, buat dan jalankan pengujian unit terhadapnya. Jika pengujian ini bergantung pada framework Android, gunakan API terpadu yang tidak terikat dengan perangkat, seperti API androidx.test. Konsistensi ini memungkinkan Anda menjalankan pengujian secara lokal tanpa menggunakan emulator atau perangkat fisik.

Jika pengujian Anda mengandalkan resource, aktifkan opsi includeAndroidResources di file build.gradle aplikasi Anda. Pengujian unit Anda akan dapat mengakses versi terkompilasi dari resource, memungkinkan pengujian berjalan lebih cepat dan akurat.

app/build.gradle

    android {
        // ...

        testOptions {
            unitTests {
                includeAndroidResources = true
            }
        }
    }
    

Pengujian unit lokal

Jika memungkinkan, gunakan AndroidX Test API agar pengujian unit Anda dapat berjalan pada perangkat atau emulator. Untuk pengujian yang selalu dijalankan pada mesin pengembangan yang menggunakan JVM, Anda dapat menggunakan Robolectric.

Robolectric menyimulasikan waktu proses untuk Android 4.1 (API level 16) atau lebih tinggi dan memberikan objek palsu yang dikelola komunitas yang disebut shadows. Fungsionalitas ini memungkinkan Anda menguji kode yang bergantung pada framework tanpa perlu menggunakan emulator atau objek tiruan. Robolectric mendukung aspek platform Android berikut:

  • Siklus proses komponen
  • Loop peristiwa
  • Semua resource

Pengujian unit berinstrumen

Anda dapat menjalankan pengujian unit berinstrummen pada perangkat fisik atau emulator. Namun, bentuk pengujian ini melibatkan waktu eksekusi yang jauh lebih lambat daripada pengujian unit lokal, jadi sebaiknya andalkan metode ini hanya ketika Anda perlu mengevaluasi perilaku aplikasi terhadap hardware perangkat yang sebenarnya.

Saat menjalankan pengujian berinstrumen, AndroidX Test menggunakan thread berikut:

  • Thread utama, juga dikenal sebagai "UI thread" atau "thread aktivitas", tempat terjadinya interaksi UI dan peristiwa siklus proses.
  • Thread berinstrumen, tempat sebagian besar pengujian Anda dijalankan. Saat rangkaian pengujian Anda dimulai, class AndroidJUnitTest memulai thread ini.

Jika Anda memerlukan pengujian untuk dijalankan pada thread utama, beri anotasi pada pengujian tersebut menggunakan @UiThreadTest.

Menulis pengujian sedang

Selain menguji setiap unit aplikasi dengan menjalankan pengujian kecil, Anda harus memvalidasi perilaku aplikasi dari tingkat modul. Caranya, tulis pengujian sedang, yang merupakan pengujian integrasi yang memvalidasi kolaborasi dan interaksi sekelompok unit.

Gunakan struktur aplikasi Anda dan contoh pengujian sedang berikut (guna meningkatkan cakupan) untuk menentukan cara terbaik untuk merepresentasikan kelompok unit dalam aplikasi Anda:

  1. Interaksi antara tampilan dan model tampilan, seperti menguji objek Fragment, memvalidasi XML tata letak, atau mengevaluasi logika data binding dari objek ViewModel.
  2. Pengujian dalam lapisan repositori aplikasi Anda, yang memverifikasi bahwa berbagai sumber data dan objek akses data (DAO) Anda berinteraksi seperti yang diharapkan.
  3. Slice vertikal aplikasi Anda, menguji interaksi pada layar tertentu. Pengujian tersebut memverifikasi interaksi di seluruh lapisan tumpukan aplikasi Anda.
  4. Pengujian multi-fragment yang mengevaluasi area tertentu dari aplikasi Anda. Berbeda dengan jenis pengujian sedang lain yang disebutkan dalam daftar ini, jenis pengujian ini biasanya memerlukan perangkat nyata karena interaksi yang sedang diuji melibatkan beberapa elemen UI.

Untuk menjalankan pengujian ini, lakukan hal berikut:

  1. Gunakan metode dari library Espresso Intents. Untuk menyederhanakan informasi yang Anda teruskan dalam pengujian ini, gunakan objek palsu dan stubbing.
  2. Gabungkan penggunaan IntentSubject dan pernyataan berbasis Truth untuk memverifikasi intent yang diperoleh.

Menggunakan Espresso saat menjalankan pengujian sedang berinstrumen

Espresso membantu membuat tugas tetap tersinkronkan saat Anda melakukan interaksi UI yang serupa dengan hal berikut di perangkat atau di Robolectric:

  • Menjalankan tindakan pada objek View.
  • Menilai bagaimana pengguna dengan kebutuhan aksesibilitas dapat menggunakan aplikasi Anda.
  • Menemukan dan mengaktifkan item dalam objek RecyclerView dan AdapterView.
  • Memvalidasi status intent keluar.
  • Memverifikasi struktur DOM dalam objek WebView.

Untuk mempelajari lebih lanjut interaksi ini dan cara menggunakannya dalam pengujian aplikasi Anda, lihat panduan Espresso.

Menulis pengujian besar

Meskipun penting untuk menguji setiap class dan modul dalam aplikasi Anda secara terpisah, memvalidasi alur kerja end-to-end yang memandu pengguna menyelesaikan berbagai modul dan fitur juga penting. Jenis pengujian ini membentuk hambatan yang tidak terhindarkan dalam kode Anda, tetapi Anda dapat meminimalkan efek ini dengan memvalidasi aplikasi yang semirip mungkin dengan produk jadi yang asli.

Jika aplikasi cukup kecil, Anda mungkin hanya memerlukan satu rangkaian pengujian besar untuk mengevaluasi fungsionalitas aplikasi Anda secara menyeluruh. Jika tidak, Anda harus membagi paket pengujian besar Anda berdasarkan kepemilikan tim, vertikal fungsional, atau tujuan pengguna.

Biasanya, akan lebih baik untuk menguji aplikasi Anda di perangkat yang diemulasi atau layanan berbasis cloud seperti Firebase Test Lab, daripada di perangkat fisik, karena Anda dapat menguji berbagai kombinasi ukuran layar dan konfigurasi hardware dengan lebih mudah dan cepat.

Dukungan sinkronisasi di Espresso

Selain mendukung pengujian instrumentasi berukuran sedang, Espresso menyediakan dukungan untuk sinkronisasi saat menyelesaikan tugas berikut dalam pengujian besar:

  • Menyelesaikan alur kerja yang melintasi batas proses aplikasi Anda. Hanya tersedia di Android 8.0 (API level 26) dan lebih tinggi.
  • Melacak operasi latar belakang yang sudah lama berjalan di dalam aplikasi Anda.
  • Melakukan pengujian di luar perangkat.

Untuk mempelajari lebih lanjut interaksi ini dan cara menggunakannya dalam pengujian aplikasi Anda, lihat panduan Espresso.

Menyelesaikan tugas pengujian lainnya menggunakan AndroidX Test

Bagian ini menjelaskan cara menggunakan elemen AndroidX Test untuk lebih mempersempit pengujian aplikasi Anda.

Membuat pernyataan yang lebih mudah dibaca menggunakan Truth

Tim Guava menyediakan library pernyataan lancar yang disebut Truth. Anda dapat menggunakan library ini sebagai alternatif untuk pernyataan berbasis JUnit atau Hamcrest saat membuat langkah validasi—atau langkah then—pengujian Anda.

Umumnya, Anda menggunakan Truth untuk menyatakan bahwa objek tertentu memiliki properti tertentu menggunakan frasa yang berisi kondisi yang Anda uji, seperti berikut ini:

  • assertThat(object).hasFlags(FLAGS)
  • assertThat(object).doesNotHaveFlags(FLAGS)
  • assertThat(intent).hasData(URI)
  • assertThat(extras).string(string_key).equals(EXPECTED)

AndroidX Test mendukung beberapa subjek tambahan untuk Android untuk membuat pernyataan berbasis Truth lebih mudah dibuat:

AndroidX Test API membantu Anda melakukan tugas umum terkait dengan pengujian aplikasi seluler, yang dibahas di bagian berikutnya.

Menulis pengujian UI

Espresso memungkinkan Anda menemukan dan berinteraksi secara terprogram dengan elemen UI di aplikasi Anda dengan cara yang aman bagi thread. Untuk mempelajari lebih lanjut, lihat panduan Espresso.

Menjalankan pengujian UI

Class AndroidJUnitRunner menentukan runner pengujian JUnit berbasis instrumentasi yang memungkinkan Anda menjalankan class pengujian gaya JUnit 3 atau JUnit 4 di perangkat Android. Runner pengujian memfasilitasi pemuatan paket pengujian dan aplikasi yang sedang diuji ke perangkat atau emulator, menjalankan pengujian Anda, dan melaporkan hasilnya.

Untuk meningkatkan keandalan pengujian ini lebih lanjut, gunakan Android Test Orchestrator, yang menjalankan setiap pengujian UI di sandbox Instrumentation-nya sendiri. Arsitektur ini mengurangi status yang dibagikan antara pengujian dan mengisolasi error aplikasi berdasarkan per pengujian. Untuk informasi selengkapnya tentang manfaat yang diberikan Android Test Orchestrator saat Anda menguji aplikasi, lihat panduan Android Test Orchestrator.

Berinteraksi dengan elemen yang terlihat

UI Automator API memungkinkan Anda berinteraksi dengan elemen yang terlihat di perangkat, terlepas dari aktivitas atau fragmen yang memiliki fokus.

Perhatian: Cobalah untuk menguji aplikasi Anda menggunakan UI Automator hanya jika aplikasi Anda harus berinteraksi dengan UI sistem atau aplikasi lain untuk memenuhi kasus penggunaan kritis. Karena UI Automator berinteraksi dengan UI sistem tertentu, Anda harus menjalankan kembali dan memperbaiki pengujian UI Automator setelah setiap upgrade versi platform dan setelah setiap rilis baru layanan Google Play.

Sebagai alternatif menggunakan UI Automator, sebaiknya tambahkan pengujian hermetic atau pisahkan pengujian besar Anda agar menjadi serangkaian pengujian kecil dan sedang. Secara khusus, berfokuslah pada pengujian satu bagian komunikasi antar-aplikasi pada suatu waktu, seperti mengirim informasi ke aplikasi lain dan merespons hasil intent. Alat Espresso-Intents dapat membantu Anda menulis pengujian yang lebih kecil ini.

Menambahkan pemeriksaan aksesibilitas untuk memvalidasi kegunaan umum

Antarmuka aplikasi Anda harus mengizinkan semua pengguna, termasuk yang memerlukan aksesibilitas, untuk berinteraksi dengan perangkat dan menyelesaikan tugas dengan lebih mudah di aplikasi Anda.

Untuk membantu memvalidasi aksesibilitas aplikasi Anda, library pengujian Android menyediakan beberapa bagian fungsionalitas bawaan, yang dibahas pada bagian berikutnya. Untuk mempelajari lebih lanjut cara memvalidasi kegunaan aplikasi Anda untuk berbagai jenis pengguna, lihat panduan tentang menguji aksesibilitas aplikasi Anda.

Robolectric

Aktifkan pemeriksaan aksesibilitas dengan menyertakan anotasi @AccessibilityChecks di awal paket pengujian, seperti yang ditunjukkan dalam cuplikan kode berikut:

Kotlin

    import org.robolectric.annotation.AccessibilityChecks

    @AccessibilityChecks
    class MyTestSuite {
        // Your tests here.
    }
    

Java

    import org.robolectric.annotation.AccessibilityChecks;

    @AccessibilityChecks
    public class MyTestSuite {
        // Your tests here.
    }
    

Espresso

Aktifkan pemeriksaan aksesibilitas dengan memanggil AccessibilityChecks.enable() dalam metode setUp() di paket pengujian, seperti yang ditunjukkan dalam cuplikan kode berikut.

Untuk informasi selengkapnya tentang cara menafsirkan hasil pemeriksaan aksesibilitas ini, lihat panduan memeriksa aksesibilitas Espresso.

Kotlin

    import androidx.test.espresso.accessibility.AccessibilityChecks

    @Before
    fun setUp() {
        AccessibilityChecks.enable()
    }
    

Java

    import androidx.test.espresso.accessibility.AccessibilityChecks;

    @Before
    public void setUp() {
        AccessibilityChecks.enable();
    }
    

Mendorong siklus proses aktivitas dan fragmen

Gunakan class ActivityScenario dan FragmentScenario untuk menguji bagaimana aktivitas dan fragmen aplikasi Anda merespons gangguan tingkat sistem dan perubahan konfigurasi. Untuk mempelajari lebih lanjut, lihat panduan tentang cara menguji aktivitas dan menguji fragmen.

Mengelola siklus proses layanan

AndroidX Test menyertakan kode untuk mengelola siklus proses layanan utama. Untuk mempelajari cara menentukan aturan ini, lihat panduan Aturan JUnit4.

Mengevaluasi semua varian perilaku yang berbeda menurut versi SDK

Jika perilaku aplikasi Anda bergantung pada versi SDK perangkat, gunakan anotasi @SdkSuppress, dengan meneruskan nilai untuk minSdkVersion atau maxSdkVersion bergantung pada cara Anda mencabangkan logika aplikasi Anda:

Kotlin

    @Test
    @SdkSuppress(maxSdkVersion = 27)
    fun testButtonClickOnOreoAndLower() {
        // ...
    }

    @Test
    @SdkSuppress(minSdkVersion = 28)
    fun testButtonClickOnPieAndHigher() {
        // ...
    }
    

Java

    @Test
    @SdkSuppress(maxSdkVersion = 27)
    public void testButtonClickOnOreoAndLower() {
        // ...
    }

    @Test
    @SdkSuppress(minSdkVersion = 28)
    public void testButtonClickOnPieAndHigher() {
        // ...
    }
    

Referensi lainnya

Untuk informasi selengkapnya tentang pengujian pada Android, lihat referensi berikut.

Contoh

Codelab