Dasar-dasar pengujian aplikasi Android

Halaman ini menguraikan prinsip inti pengujian aplikasi Android, termasuk praktik terbaik terpusat dan manfaatnya.

Manfaat pengujian

Pengujian adalah bagian integral dari proses pengembangan aplikasi. Dengan menjalankan pengujian terhadap aplikasi Anda secara konsisten, Anda dapat memverifikasi ketepatan dan fungsi aplikasi perilaku, dan kegunaan sebelum Anda merilisnya ke publik.

Anda dapat menguji aplikasi secara manual dengan membukanya. Anda mungkin menggunakan menggunakan perangkat dan emulator yang berbeda, mengubah bahasa sistem, dan mencoba membuat setiap kesalahan pengguna atau melintasi setiap alur pengguna.

Namun, pengujian manual diskalakan dengan skala yang buruk, dan mudah untuk diabaikan regresi dalam perilaku aplikasi Anda. Pengujian otomatis melibatkan penggunaan alat yang melakukan pengujian untuk Anda, lebih cepat, lebih dapat diulang, dan umumnya memberi Anda lebih banyak masukan yang dapat ditindaklanjuti tentang aplikasi di awal pengembangan {i>checkout<i}.

Jenis pengujian di Android

Aplikasi seluler sangatlah rumit dan harus berfungsi dengan baik di banyak lingkungan. Sebagai Jadi, ada banyak jenis pengujian.

Subjek

Misalnya, ada berbagai jenis pengujian, bergantung pada subjeknya:

  • Pengujian fungsional: apakah aplikasi saya melakukan fungsinya?
  • Pengujian performa: apakah ini melakukannya dengan cepat dan efisien?
  • Pengujian aksesibilitas: apakah berfungsi dengan baik dengan layanan aksesibilitas?
  • Pengujian kompatibilitas: apakah fitur ini berfungsi dengan baik di setiap perangkat dan level API?

Cakupan

Pengujian juga bervariasi, bergantung pada ukuran, atau tingkat isolasi:

  • Pengujian unit atau pengujian kecil hanya memverifikasi sebagian kecil aplikasi, seperti metode atau class.
  • Pengujian end-to-end atau pengujian besar memverifikasi bagian aplikasi yang lebih besar di waktu yang sama, seperti seluruh layar atau alur pengguna.
  • Pengujian sedang berada di antara pengujian dan memeriksa integrasi antara dua atau unit lebih banyak.
Pengujian dapat berupa kecil, sedang, atau besar.
Gambar 1: Cakupan pengujian dalam aplikasi standar.

Ada banyak cara untuk mengklasifikasikan pengujian. Namun, perbedaan yang paling penting bagi developer aplikasi adalah tempat pengujian dijalankan.

Pengujian berinstrumen versus lokal

Anda dapat menjalankan pengujian di perangkat Android atau di komputer lain:

  • Pengujian berinstrumen berjalan pada perangkat Android, baik fisik maupun emulasi. Aplikasi ini dibuat dan diinstal bersama aplikasi pengujian yang memasukkan perintah dan membaca status. Pengujian berinstrumen biasanya adalah pengujian UI, meluncurkan aplikasi dan kemudian berinteraksi dengannya.
  • Pengujian lokal dijalankan di mesin pengembangan atau server, sehingga juga disebut pengujian sisi host. Mereka biasanya kecil dan cepat, mengisolasi subjek yang diuji dari bagian aplikasi lainnya.
Pengujian bisa dijalankan sebagai uji instrumentasi pada perangkat, atau pengujian lokal pada mesin pengembangan Anda.
Gambar 2: Berbagai jenis pengujian bergantung pada tempat pengujian tersebut dijalankan.

Tidak semua pengujian unit bersifat lokal, dan tidak semua pengujian menyeluruh berjalan pada perangkat. Contoh:

  • Pengujian lokal besar: Anda dapat menggunakan simulator Android yang berjalan secara lokal, seperti sebagai Robolectric.
  • Pengujian berinstrumen kecil: Anda dapat memverifikasi bahwa kode Anda berfungsi dengan baik dengan fitur framework Anda, seperti database SQLite. Anda dapat menjalankan pengujian ini pada beberapa perangkat untuk memeriksa integrasi dengan beberapa versi SQLite.

Contoh

Cuplikan berikut menunjukkan cara berinteraksi dengan UI dalam pengujian UI berinstrumen yang mengklik elemen dan memverifikasi bahwa elemen lain ditampilkan.

Espresso

// When the Continue button is clicked
onView(withText("Continue"))
    .perform(click())

// Then the Welcome screen is displayed
onView(withText("Welcome"))
    .check(matches(isDisplayed()))

Compose UI

// When the Continue button is clicked
composeTestRule.onNodeWithText("Continue").performClick()

// Then the Welcome screen is displayed
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()

Cuplikan ini menunjukkan bagian dari pengujian unit untuk ViewModel (lokal, sisi host ):

// Given an instance of MyViewModel
val viewModel = MyViewModel(myFakeDataRepository)

// When data is loaded
viewModel.loadData()

// Then it should be exposing data
assertTrue(viewModel.data != null)

Menentukan strategi pengujian

Idealnya, Anda akan menguji setiap baris kode dalam aplikasi di setiap perangkat yang kompatibel dengan aplikasi Anda. Sayangnya, pendekatan ini terlalu lambat dan mahal agar terlihat praktis.

Strategi pengujian yang baik akan menemukan keseimbangan yang sesuai antara fidelitas pengujian, kecepatan, dan keandalannya. Kesamaan lingkungan pengujian dengan perangkat sesungguhnya menentukan {i>fidelity <i}pengujian. Pengujian {i>fidelity <i}yang lebih tinggi dijalankan pada perangkat yang diemulasikan atau perangkat fisik itu sendiri. Pengujian {i>fidelity <i}yang lebih rendah mungkin berjalan di JVM workstation lokal Anda. Pengujian {i>high-fidelity <i}sering kali lebih lambat dan membutuhkan lebih banyak sumber daya, jadi tidak semua pengujian harus berupa pengujian {i>high-fidelity<i}.

Pengujian tidak stabil

Error terjadi bahkan dalam pengujian yang dirancang dan diimplementasikan dengan benar. Misalnya, saat menjalankan pengujian di perangkat sebenarnya, update otomatis dapat dimulai di di tengah pengujian dan menyebabkannya gagal. Kondisi perlombaan yang halus dalam kode Anda mungkin hanya terjadi dalam persentase kecil. Pengujian yang tidak lulus 100% kriteria waktu yang tidak stabil.

Arsitektur yang dapat diuji

Dengan arsitektur aplikasi yang dapat diuji, kode mengikuti struktur yang memungkinkan Anda untuk dengan mudah menguji bagian-bagiannya secara terpisah. Arsitektur yang dapat diuji memiliki keuntungan lainnya, seperti keterbacaan, pengelolaan, skalabilitas, dan dapat digunakan kembali.

Arsitektur yang tidak dapat diuji menghasilkan hal berikut:

  • Pengujian yang lebih besar, lebih lambat, dan lebih tidak stabil. Kelas yang tidak dapat diuji unit mungkin memiliki akan tercakup dalam pengujian integrasi atau pengujian UI yang lebih besar.
  • Lebih sedikit peluang untuk menguji berbagai skenario. Pengujian yang lebih besar akan lebih lambat, jadi menguji semua kemungkinan keadaan aplikasi mungkin tidak realistis.

Untuk mempelajari pedoman arsitektur lebih lanjut, lihat panduan aplikasi arsitektur ini.

Pendekatan untuk memisahkan

Jika Anda dapat mengekstrak sebagian fungsi, class, atau modul dari fungsi, class, atau modul lainnya, lebih mudah, dan lebih efektif. Praktik ini dikenal sebagai memisahkan, dan itu adalah konsep yang paling penting untuk arsitektur yang dapat diuji.

Teknik pemisahan umum meliputi:

  • Memisahkan aplikasi menjadi lapisan seperti Presentasi, Domain, dan Data. Anda dapat juga membagi aplikasi menjadi modul, satu per fitur.
  • Hindari menambahkan logika ke entity yang memiliki dependensi besar, seperti aktivitas dan fragmen Anda. Gunakan class ini sebagai titik masuk ke framework dan memindahkan UI dan logika bisnis di tempat lain, seperti ke Composable, ViewModel, atau lapisan domain tambahan.
  • Hindari dependensi framework langsung di class yang berisi logika bisnis. Misalnya, jangan gunakan Konteks Android di ViewModels.
  • Membuat dependensi mudah untuk diganti. Misalnya, gunakan antarmuka alih-alih implementasi konkret. Gunakan Injeksi dependensi meskipun Anda tidak menggunakan framework DI.

Langkah berikutnya

Sekarang setelah Anda tahu mengapa Anda harus menguji dan dua jenis pengujian utama, Anda bisa baca Apa yang perlu diuji.

Atau, jika Anda ingin membuat pengujian pertama dan belajar langsung, centang lihat Codelab pengujian.