Menguji ViewModels dan LiveData

1. Sebelum memulai

Di codelab sebelumnya, Anda telah mempelajari cara menggunakan ViewModel untuk menangani logika bisnis, serta LiveData untuk UI reaktif. Dalam codelab ini, Anda akan mempelajari cara menulis pengujian unit untuk memastikan kode ViewModel berfungsi dengan benar.

Prasyarat

  • Anda telah membuat direktori pengujian di Android Studio.
  • Anda telah menulis pengujian unit dan instrumentasi di Android Studio.
  • Anda telah menambahkan dependensi Gradle ke project Android.

Yang akan Anda pelajari

  • Cara menulis pengujian unit untuk ViewModel dan LiveData.

Yang Anda butuhkan

  • Komputer yang dilengkapi Android Studio.
  • Kode solusi untuk aplikasi Cupcake.

Mendownload kode awal untuk codelab ini

Dalam codelab ini, Anda akan menambahkan uji instrumentasi ke aplikasi Cupcake dari kode solusi sebelumnya.

Untuk mendapatkan kode codelab ini dan membukanya di Android Studio, lakukan hal berikut.

Mendapatkan kode

  1. Klik URL yang diberikan. Tindakan ini akan membuka halaman GitHub project di browser.
  2. Periksa dan konfirmasi nama cabang yang cocok dengan nama cabang yang ditentukan dalam codelab. Misalnya, dalam screenshot berikut, nama cabang adalah main (utama).

fe29aa9112862a93.png

  1. Di halaman GitHub project, klik tombol Code yang akan menampilkan pop-up.

5b0a76c50478a73f.png

  1. Pada pop-up, klik tombol Download ZIP untuk menyimpan project di komputer. Tunggu download selesai.
  2. Temukan file di komputer Anda (mungkin di folder Downloads).
  3. Klik dua kali pada file ZIP untuk mengekstraknya. Tindakan ini akan membuat folder baru yang berisi file project.

Membuka project di Android Studio

  1. Mulai Android Studio.
  2. Di jendela Welcome to Android Studio, klik Open.

a065e3d575fe607b.png

Catatan: Jika Android Studio sudah terbuka, pilih opsi menu File > Open.

4f3b1e628c7695f1.png

  1. Di file browser, buka lokasi folder project yang telah diekstrak (kemungkinan ada di folder Downloads).
  2. Klik dua kali pada folder project tersebut.
  3. Tunggu Android Studio membuka project.
  4. Klik tombol Run 11c34fc5e516fb1c.png untuk membangun dan menjalankan aplikasi. Pastikan aplikasi dibangun seperti yang diharapkan.

2. Ringkasan aplikasi awal

Aplikasi Cupcake terdiri dari layar utama yang menampilkan layar pesanan dengan tiga opsi jumlah cupcake. Dengan mengklik opsi, Anda akan berpindah ke layar pemilihan rasa, lalu Anda diarahkan ke layar pemilihan tanggal pengambilan pesanan. Setelah itu, Anda dapat mengirimkan pesanan ke aplikasi lain. Anda dapat membatalkan pesanan di salah satu tahap ini.

3. Membuat direktori pengujian unit

Buat direktori pengujian unit untuk aplikasi Cupcake seperti yang telah Anda lakukan di codelab sebelumnya.

4. Membuat class pengujian unit

Buat class baru bernama ViewModelTests.kt.

5. Menambahkan dependensi yang diperlukan

Tambahkan dependensi berikut ke project Anda:

testImplementation 'junit:junit:4.+'
testImplementation 'androidx.arch.core:core-testing:2.1.0'

Sekarang sinkronkan project Anda.

6. Menulis pengujian ViewModel

Mari kita mulai dengan pengujian sederhana. Hal pertama yang kita lakukan saat berinteraksi dengan aplikasi di perangkat atau emulator adalah memilih jumlah cupcake. Jadi pertama-tama kita akan menguji metode setQuantity() di OrderViewModel, dan memeriksa nilai objek quantity LiveData.

Variabel quantity, yang akan kita uji, adalah instance LiveData. Pengujian objek LiveData memerlukan langkah tambahan, dan di sinilah dependensi yang telah kita tambahkan akan berperan. Kita menggunakan LiveData untuk memperbarui UI segera setelah nilai berubah. UI kita berjalan pada "thread utama". Bukan masalah jika Anda tidak terbiasa dengan pembuatan thread dan konkurensi karena kami akan membahasnya secara mendalam di codelab lainnya. Untuk saat ini, dalam konteks aplikasi Android, anggap thread utama sebagai thread UI. Kode yang menampilkan UI kepada pengguna yang berjalan di thread ini. Kecuali jika ditentukan lain, pengujian unit mengasumsikan bahwa semua UI berjalan di thread utama. Namun, karena objek LiveData tidak dapat mengakses thread utama, kita harus menyatakan secara eksplisit bahwa objek LiveData tidak boleh memanggil thread utama.

  1. Untuk menentukan bahwa objek LiveData tidak boleh memanggil thread utama, kita perlu menyediakan aturan pengujian tertentu setiap kali menguji objek LiveData.
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
  1. Sekarang kita dapat membuat fungsi bernama quantity_twelve_cupcakes(). Dalam metode ini, buat instance OrderViewModel.
  2. Dalam pengujian ini, Anda akan memeriksa untuk memastikan objek quantity di OrderViewModel diperbarui saat setQuantity dipanggil. Namun, sebelum memanggil metode apa pun atau menggunakan data di OrderViewModel, penting untuk diperhatikan bahwa saat menguji nilai objek LiveData, objek harus diamati agar perubahan dapat ditampilkan. Cara mudah untuk melakukannya adalah dengan menggunakan metode observeForever. Panggil metode observeForever pada objek quantity. Metode ini memerlukan ekspresi lambda, tetapi boleh kosong.
  3. Lalu, panggil metode setQuantity() dengan meneruskan 12 sebagai parameter.
val viewModel = OrderViewModel()
viewModel.quantity.observeForever {}
viewModel.setQuantity(12)
  1. Kita dapat dengan aman menyimpulkan bahwa nilai objek quantity adalah 12. Perlu diketahui bahwa objek LiveData bukanlah nilai itu sendiri. Nilai dimuat dalam properti yang disebut value. Buat pernyataan berikut:
assertEquals(12, viewModel.quantity.value)

Pengujian Anda akan terlihat seperti ini:

@Test
fun quantity_twelve_cupcakes() {
   val viewModel = OrderViewModel()
   viewModel.quantity.observeForever {}
   viewModel.setQuantity(12)
   assertEquals(12, viewModel.quantity.value)
}

Jalankan pengujian. Selamat, Anda baru saja menulis pengujian unit LiveData pertama yang merupakan keterampilan penting dalam pengembangan Android modern. Pengujian ini tidak menguji banyak logika bisnis. Jadi, mari menulis pengujian yang sedikit lebih menggunakan logika bisnis.

Salah satu fungsi utama OrderViewModel adalah menghitung harga pesanan. Hal ini terjadi saat kita memilih jumlah cupcake, dan memilih tanggal pengambilan. Penghitungan harga dilakukan dengan metode pribadi sehingga pengujian tidak dapat memanggil metode ini secara langsung. Hanya metode lain di OrderViewModel yang dapat memanggilnya. Metode ini bersifat publik. Jadi, kita akan memanggilnya agar memicu penghitungan harga sehingga kita dapat memeriksa apakah nilai harganya sesuai dengan harapan atau tidak.

Praktik terbaik

Harga diperbarui saat jumlah cupcake dan juga tanggal dipilih. Meskipun keduanya harus diuji, umumnya lebih baik hanya menguji satu fungsi. Oleh karena itu, kita akan membuat metode terpisah untuk setiap pengujian: satu fungsi guna menguji harga saat jumlah diperbarui, dan fungsi terpisah untuk menguji harga saat tanggal diperbarui. Kami tidak ingin hasil pengujian gagal dengan alasan pengujian yang berbeda gagal.

  1. Buat metode yang disebut price_twelve_cupcakes() dan anotasikan sebagai pengujian.
  2. Dalam metode ini, buat instance OrderViewModel dan panggil metode setQuantity() dengan meneruskan 12 sebagai parameter.
val viewModel = OrderViewModel()
viewModel.setQuantity(12)
  1. Dengan melihat PRICE_PER_CUPCAKE di OrderViewModel, kita jadi tahu harga setiap cupcake adalah $2,00. Kita juga dapat melihat bahwa resetOrder() dipanggil setiap kali ViewModel diinisialisasi, dan dalam metode ini, tanggal default adalah tanggal hari ini, dan PRICE_FOR_SAME_DAY_PICKUP adalah $3,00. Jadi, 12 * 2 + 3 = 27. Setelah memilih 12 cupcake, kita memperkirakan nilai variabel price menjadi $27,00. Jadi, mari buat pernyataan bahwa nilai yang diharapkan sebesar $27,00 sama dengan nilai objek price LiveData.
assertEquals("$27.00", viewModel.price.value)

Sekarang jalankan pengujian.

Gagal!

17c8a24e4d7d635d.png

Hasil pengujian menyatakan bahwa nilai sebenarnya adalah null. Ada penjelasan untuk hal ini. Jika melihat variabel price di OrderViewModel, Anda akan melihat ini:

val price: LiveData<String> = Transformations.map(_price) {
   // Format the price into the local currency and return this as LiveData<String>
   NumberFormat.getCurrencyInstance().format(it)
}

Ini adalah contoh alasan LiveData harus diamati dalam pengujian. Nilai price disetel dengan menggunakan Transformation. Pada dasarnya, kode ini menggunakan nilai yang telah kita setel ke price dan mengubahnya ke format mata uang sehingga kita tidak perlu melakukannya secara manual. Namun, kode ini memiliki implikasi lainnya. Saat mengubah objek LiveData, kode tidak akan dipanggil kecuali jika diperlukan. Hal ini akan menghemat resource di perangkat seluler. Kode hanya akan dipanggil jika kita mengamati objek untuk perubahan. Tentu saja hal ini dilakukan di aplikasi kita, tetapi kita juga perlu melakukan hal yang sama untuk pengujian.

  1. Dalam metode pengujian, tambahkan baris berikut sebelum menetapkan jumlah:
viewModel.price.observeForever {}

Pengujian Anda akan terlihat seperti ini:

@Test
fun price_twelve_cupcakes() {
   val viewModel = OrderViewModel()
   viewModel.price.observeForever {}
   viewModel.setQuantity(12)
   assertEquals("$27.00", viewModel.price.value)
}

Sekarang, pengujian yang akan Anda jalankan seharusnya lulus.

7. Kode solusi

8. Selamat

Dalam codelab ini, kita telah:

  • Mempelajari cara menyiapkan pengujian LiveData.
  • Mempelajari cara menguji LiveData itu sendiri.
  • Mempelajari cara menguji LiveData yang ditransformasi.
  • Mempelajari cara mengamati LiveData dalam pengujian unit.