Dasar-Dasar Pengujian

Codelab ini adalah bagian dari kursus Android Lanjutan di Kotlin. Anda akan mendapatkan manfaat maksimal dari kursus ini jika menyelesaikan codelab secara berurutan, tetapi ini tidak bersifat wajib. Semua codelab kursus tercantum di halaman landing codelab Android Lanjutan di Kotlin.

Pengantar

Saat menerapkan fitur pertama aplikasi pertama, Anda mungkin menjalankan kode untuk memverifikasi bahwa kode tersebut berfungsi seperti yang diharapkan. Anda melakukan pengujian, meskipun pengujian manual. Saat terus menambahkan dan memperbarui fitur, Anda mungkin juga terus menjalankan kode dan memverifikasi bahwa kode tersebut berfungsi. Namun, melakukan hal ini secara manual setiap saat melelahkan, rentan terhadap kesalahan, dan tidak dapat diskalakan.

Komputer sangat bagus dalam penskalaan dan otomatisasi. Jadi, developer di perusahaan besar dan kecil menulis pengujian otomatis, yaitu pengujian yang dijalankan oleh software dan tidak mengharuskan Anda mengoperasikan aplikasi secara manual untuk memverifikasi apakah kode berfungsi.

Yang akan Anda pelajari dalam serangkaian codelab ini adalah cara membuat kumpulan pengujian (dikenal sebagai suite pengujian) untuk aplikasi dunia nyata.

Codelab pertama ini mencakup dasar-dasar pengujian di Android. Anda akan menulis pengujian pertama dan mempelajari cara menguji LiveData dan ViewModel.

Yang harus sudah Anda ketahui

Anda harus memahami:

Yang akan Anda pelajari

Anda akan mempelajari topik berikut:

  • Cara menulis dan menjalankan pengujian unit di Android
  • Cara menggunakan Pengembangan Berbasis Pengujian
  • Cara memilih pengujian berinstrumen dan pengujian lokal

Anda akan mempelajari pustaka dan konsep kode berikut:

Yang akan Anda lakukan

  • Menyiapkan, menjalankan, dan menafsirkan pengujian lokal dan berinstrumen di Android.
  • Menulis pengujian unit di Android menggunakan JUnit4 dan Hamcrest.
  • Tulis pengujian LiveData dan ViewModel sederhana.

Dalam serangkaian codelab ini, Anda akan mengerjakan aplikasi TO-DO Notes. Aplikasi ini memungkinkan Anda menuliskan tugas yang harus diselesaikan dan menampilkannya dalam daftar. Kemudian, Anda dapat menandainya sebagai selesai atau tidak, memfilternya, atau menghapusnya.

Aplikasi ini ditulis di Kotlin, memiliki beberapa layar, menggunakan komponen Jetpack, dan mengikuti arsitektur dari Panduan arsitektur aplikasi. Dengan mempelajari cara menguji aplikasi ini, Anda akan dapat menguji aplikasi yang menggunakan library dan arsitektur yang sama.

Untuk memulai, download kode:

Download Zip

Atau, Anda dapat membuat clone repositori GitHub untuk kode tersebut:

$ git clone https://github.com/googlecodelabs/android-testing.git
$ cd android-testing
$ git checkout starter_code

Dalam tugas ini, Anda akan menjalankan aplikasi dan menjelajahi code base.

Langkah 1: Jalankan aplikasi contoh

Setelah Anda mendownload aplikasi TO-DO, buka di Android Studio dan jalankan. Kode harus dikompilasi. Jelajahi aplikasi dengan melakukan hal berikut:

  • Buat tugas baru dengan tombol tindakan mengambang plus. Masukkan judul terlebih dahulu, lalu masukkan informasi tambahan tentang tugas. Simpan dengan FAB centang hijau.
  • Dalam daftar tugas, klik judul tugas yang baru saja Anda selesaikan dan lihat layar detail tugas tersebut untuk melihat deskripsi lainnya.
  • Dalam daftar atau di layar detail, centang kotak tugas tersebut untuk menyetel statusnya ke Selesai.
  • Kembali ke layar tugas, buka menu filter, dan filter tugas menurut status Aktif dan Selesai.
  • Buka panel navigasi, lalu klik Statistik.
  • Kembali ke layar ringkasan, dan dari menu panel navigasi, pilih Hapus selesai untuk menghapus semua tugas dengan status Selesai

Langkah 2: Pelajari kode aplikasi contoh

Aplikasi TO-DO didasarkan pada sampel pengujian dan arsitektur Architecture Blueprints yang populer (menggunakan sampel versi reactive architecture). Aplikasi mengikuti arsitektur dari Panduan arsitektur aplikasi. Aplikasi ini menggunakan ViewModel dengan Fragmen, repositori, dan Room. Jika Anda sudah terbiasa dengan salah satu contoh di bawah, aplikasi ini memiliki arsitektur yang serupa:

Lebih penting bagi Anda untuk memahami arsitektur umum aplikasi daripada memiliki pemahaman mendalam tentang logika di salah satu lapisan.

Berikut ringkasan paket yang akan Anda temukan:

Paket: com.example.android.architecture.blueprints.todoapp

.addedittask

Layar menambahkan atau mengedit tugas: Kode lapisan UI untuk menambahkan atau mengedit tugas.

.data

Lapisan data: Bagian ini berhubungan dengan lapisan data tugas. Direktori ini berisi kode database, jaringan, dan repositori.

.statistics

Layar statistik: Kode lapisan UI untuk layar statistik.

.taskdetail

Layar detail tugas: Kode lapisan UI untuk satu tugas.

.tasks

Layar tugas: Kode lapisan UI untuk daftar semua tugas.

.util

Class utilitas: Class bersama yang digunakan di berbagai bagian aplikasi, misalnya untuk tata letak tarik lalu lepas yang digunakan di beberapa layar.

Lapisan data (.data)

Aplikasi ini menyertakan lapisan jaringan simulasi, dalam paket remote, dan lapisan database, dalam paket local. Agar sederhana, dalam project ini, lapisan jaringan disimulasikan hanya dengan HashMap dengan penundaan, bukan membuat permintaan jaringan yang sebenarnya.

DefaultTasksRepository mengoordinasikan atau memediasi antara lapisan jaringan dan lapisan database, serta menampilkan data ke lapisan UI.

Lapisan UI ( .addedittask, .statistics, .taskdetail, .tasks)

Setiap paket lapisan UI berisi fragmen dan model tampilan, beserta class lain yang diperlukan untuk UI (seperti adapter untuk daftar tugas). TaskActivity adalah aktivitas yang berisi semua fragmen.

Navigasi

Navigasi untuk aplikasi dikontrol oleh komponen Navigation. Hal ini ditentukan dalam file nav_graph.xml. Navigasi dipicu di model tampilan menggunakan class Event; model tampilan juga menentukan argumen yang akan diteruskan. Fragmen mengamati Event dan melakukan navigasi sebenarnya antar-layar.

Dalam tugas ini, Anda akan menjalankan pengujian pertama.

  1. Di Android Studio, buka panel Project dan temukan tiga folder ini:
  • com.example.android.architecture.blueprints.todoapp
  • com.example.android.architecture.blueprints.todoapp (androidTest)
  • com.example.android.architecture.blueprints.todoapp (test)

Folder ini dikenal sebagai kumpulan sumber. Kumpulan sumber adalah folder yang berisi kode sumber untuk aplikasi Anda. Kumpulan sumber, yang berwarna hijau (androidTest dan test) berisi pengujian Anda. Saat membuat project Android baru, Anda akan mendapatkan tiga set sumber berikut secara default. Bagian-bagian tersebut adalah:

  • main: Berisi kode aplikasi Anda. Kode ini digunakan bersama di semua versi aplikasi yang dapat Anda build (dikenal sebagai varian build)
  • androidTest: Berisi pengujian yang dikenal sebagai pengujian berinstrumen.
  • test: Berisi pengujian yang dikenal sebagai pengujian lokal.

Perbedaan antara pengujian lokal dan pengujian berinstrumen terletak pada cara pengujian tersebut dijalankan.

Pengujian lokal (kumpulan sumber test)

Pengujian ini dijalankan secara lokal di JVM mesin pengembangan Anda dan tidak memerlukan emulator atau perangkat fisik. Oleh karena itu, mereka berjalan cepat, tetapi kesetiaannya lebih rendah, yang berarti mereka bertindak kurang seperti yang mereka lakukan di dunia nyata.

Di Android Studio, pengujian lokal diwakili oleh ikon segitiga hijau dan merah.

Pengujian berinstrumen (set sumber androidTest)

Pengujian ini berjalan di perangkat Android nyata atau yang diemulasi, sehingga mencerminkan apa yang akan terjadi di dunia nyata, tetapi juga jauh lebih lambat.

Dalam pengujian berinstrumen Android Studio, pengujian diwakili oleh Android dengan ikon segitiga hijau dan merah.

Langkah 1: Jalankan pengujian lokal

  1. Buka folder test hingga Anda menemukan file ExampleUnitTest.kt.
  2. Klik kanan, lalu pilih Run ExampleUnitTest.

Anda akan melihat output berikut di jendela Run di bagian bawah layar:

  1. Perhatikan tanda centang hijau dan luaskan hasil pengujian untuk mengonfirmasi bahwa satu pengujian yang disebut addition_isCorrect berhasil. Bagus mengetahui bahwa penambahan berfungsi seperti yang diharapkan.

Langkah 2: Buat pengujian gagal

Berikut adalah pengujian yang baru saja Anda jalankan.

ExampleUnitTest.kt

// A test class is just a normal class
class ExampleUnitTest {

   // Each test is annotated with @Test (this is a Junit annotation)
   @Test
   fun addition_isCorrect() {
       // Here you are checking that 4 is the same as 2+2
       assertEquals(4, 2 + 2)
   }
}

Perhatikan bahwa pengujian

  • adalah class di salah satu set sumber pengujian.
  • berisi fungsi yang dimulai dengan anotasi @Test (setiap fungsi adalah satu pengujian).
  • biasanya berisi pernyataan pernyataan.

Android menggunakan library pengujian JUnit untuk pengujian (dalam codelab ini JUnit4). Pernyataan dan anotasi @Test berasal dari JUnit.

Pernyataan adalah inti dari pengujian Anda. Pernyataan kode ini memeriksa apakah kode atau aplikasi Anda berperilaku seperti yang diharapkan. Dalam hal ini, pernyataan adalah assertEquals(4, 2 + 2) yang memeriksa apakah 4 sama dengan 2 + 2.

Untuk melihat seperti apa kegagalan pengujian, tambahkan pernyataan yang dapat Anda lihat dengan mudah akan gagal. Langkah ini akan memeriksa apakah 3 sama dengan 1+1.

  1. Tambahkan assertEquals(3, 1 + 1) ke pengujian addition_isCorrect.

ExampleUnitTest.kt

class ExampleUnitTest {

   // Each test is annotated with @Test (this is a Junit annotation)
   @Test
   fun addition_isCorrect() {
       assertEquals(4, 2 + 2)
       assertEquals(3, 1 + 1) // This should fail
   }
}
  1. Jalankan pengujian.
  1. Dalam hasil pengujian, perhatikan tanda X di samping pengujian.

  1. Perhatikan juga:
  • Satu pernyataan yang gagal akan membuat seluruh pengujian gagal.
  • Anda diberi tahu nilai yang diharapkan (3) versus nilai yang sebenarnya dihitung (2).
  • Anda akan diarahkan ke baris pernyataan yang gagal (ExampleUnitTest.kt:16).

Langkah 3: Jalankan pengujian berinstrumen

Pengujian berinstrumen berada di set sumber androidTest.

  1. Buka set sumber androidTest.
  2. Jalankan pengujian yang disebut ExampleInstrumentedTest.

ExampleInstrumentedTest

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        assertEquals("com.example.android.architecture.blueprints.reactive",
            appContext.packageName)
    }
}

Tidak seperti pengujian lokal, pengujian ini berjalan di perangkat (dalam contoh di bawah, ponsel Pixel 2 yang diemulasi):

Jika perangkat terpasang atau emulator berjalan, Anda akan melihat pengujian berjalan di emulator.

Dalam tugas ini, Anda akan menulis pengujian untuk getActiveAndCompleteStats, yang menghitung persentase statistik tugas aktif dan selesai untuk aplikasi Anda. Anda dapat melihat angka ini di layar statistik aplikasi.

Langkah 1: Buat class pengujian

  1. Di set sumber main, di todoapp.statistics, buka StatisticsUtils.kt.
  2. Temukan fungsi getActiveAndCompletedStats.

StatisticsUtils.kt

internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {

   val totalTasks = tasks!!.size
   val numberOfActiveTasks = tasks.count { it.isActive }
   val activePercent = 100 * numberOfActiveTasks / totalTasks
   val completePercent = 100 * (totalTasks - numberOfActiveTasks) / totalTasks

   return StatsResult(
       activeTasksPercent = activePercent.toFloat(),
       completedTasksPercent = completePercent.toFloat()
   )
  
}

data class StatsResult(val activeTasksPercent: Float, val completedTasksPercent: Float)

Fungsi getActiveAndCompletedStats menerima daftar tugas dan menampilkan StatsResult. StatsResult adalah class data yang berisi dua angka, persentase tugas yang selesai, dan persentase tugas yang aktif.

Android Studio memberi Anda alat untuk membuat stub pengujian yang membantu Anda menerapkan pengujian untuk fungsi ini.

  1. Klik kanan getActiveAndCompletedStats, lalu pilih Generate > Test.

Dialog Create Test akan terbuka:

  1. Ubah Class name: menjadi StatisticsUtilsTest (bukan StatisticsUtilsKtTest; lebih baik tidak menggunakan KT dalam nama class pengujian).
  2. Pertahankan setelan default lainnya. JUnit 4 adalah library pengujian yang sesuai. Paket tujuan sudah benar (mencerminkan lokasi class StatisticsUtils) dan Anda tidak perlu mencentang kotak centang apa pun (ini hanya menghasilkan kode tambahan, tetapi Anda akan menulis pengujian dari awal).
  3. Tekan OK

Dialog Choose Destination Directory akan terbuka:

Anda akan melakukan pengujian lokal karena fungsi Anda melakukan perhitungan matematika dan tidak akan menyertakan kode khusus Android. Jadi, tidak perlu menjalankannya di perangkat sungguhan atau yang diemulasi.

  1. Pilih direktori test (bukan androidTest) karena Anda akan menulis pengujian lokal.
  2. Klik Oke.
  3. Perhatikan class StatisticsUtilsTest yang dibuat di test/statistics/.

Langkah 2: Tulis fungsi pengujian pertama Anda

Anda akan menulis pengujian yang memeriksa:

  • jika tidak ada tugas yang selesai dan ada satu tugas aktif,
  • bahwa persentase pengujian aktif adalah 100%,
  • dan persentase tugas yang diselesaikan adalah 0%.
  1. Buka StatisticsUtilsTest.
  2. Buat fungsi bernama getActiveAndCompletedStats_noCompleted_returnsHundredZero.

StatisticsUtilsTest.kt

class StatisticsUtilsTest {

    fun getActiveAndCompletedStats_noCompleted_returnsHundredZero() {
        // Create an active task

        // Call your function

        // Check the result
    }
}
  1. Tambahkan anotasi @Test di atas nama fungsi untuk menunjukkan bahwa fungsi tersebut adalah pengujian.
  2. Buat daftar tugas.
// Create an active task 
val tasks = listOf<Task>(
            Task("title", "desc", isCompleted = false)
        )
  1. Panggil getActiveAndCompletedStats dengan tugas ini.
// Call your function
val result = getActiveAndCompletedStats(tasks)
  1. Periksa apakah result sesuai dengan yang Anda harapkan, menggunakan pernyataan.
// Check the result
assertEquals(result.completedTasksPercent, 0f)
assertEquals(result.activeTasksPercent, 100f)

Kode lengkapnya sebagai berikut.

StatisticsUtilsTest.kt

class StatisticsUtilsTest {

    @Test
    fun getActiveAndCompletedStats_noCompleted_returnsHundredZero() {

        // Create an active task (the false makes this active)
        val tasks = listOf<Task>(
            Task("title", "desc", isCompleted = false)
        )
        // Call your function
        val result = getActiveAndCompletedStats(tasks)

        // Check the result
        assertEquals(result.completedTasksPercent, 0f)
        assertEquals(result.activeTasksPercent, 100f)
    }
}
  1. Jalankan pengujian (Klik kanan StatisticsUtilsTest, lalu pilih Run).

Hasilnya akan lulus:

Langkah 3: Tambahkan dependensi Hamcrest

Karena pengujian Anda berfungsi sebagai dokumentasi tentang apa yang dilakukan kode Anda, akan lebih baik jika pengujian tersebut mudah dibaca oleh manusia. Bandingkan dua pernyataan berikut:

assertEquals(result.completedTasksPercent, 0f)

// versus

assertThat(result.completedTasksPercent, `is`(0f))

Pernyataan kedua lebih mirip kalimat manusia. Ditulis menggunakan framework pernyataan yang disebut Hamcrest. Alat bagus lainnya untuk menulis pernyataan yang mudah dibaca adalah Truth library. Anda akan menggunakan Hamcrest dalam codelab ini untuk menulis pernyataan.

  1. Buka build.grade (Module: app) dan tambahkan dependensi berikut.

app/build.gradle

dependencies {
    // Other dependencies
    testImplementation "org.hamcrest:hamcrest-all:$hamcrestVersion"
}

Biasanya, Anda menggunakan implementation saat menambahkan dependensi, tetapi di sini Anda menggunakan testImplementation. Saat Anda siap membagikan aplikasi kepada dunia, sebaiknya jangan memperbesar ukuran APK dengan kode atau dependensi pengujian apa pun di aplikasi Anda. Anda dapat menentukan apakah library harus disertakan dalam kode utama atau pengujian dengan menggunakan konfigurasi gradle. Konfigurasi yang paling umum adalah:

  • implementation—Dependensi tersedia di semua set sumber, termasuk set sumber pengujian.
  • testImplementation—Dependensi hanya tersedia di set sumber pengujian.
  • androidTestImplementation—Dependensi hanya tersedia di set sumber androidTest.

Konfigurasi yang Anda gunakan menentukan tempat dependensi dapat digunakan. Jika Anda menulis:

testImplementation "org.hamcrest:hamcrest-all:$hamcrestVersion"

Artinya, Hamcrest hanya akan tersedia di set sumber pengujian. Tindakan ini juga memastikan bahwa Hamcrest tidak akan disertakan dalam aplikasi akhir Anda.

Langkah 4: Menggunakan Hamcrest untuk menulis pernyataan

  1. Perbarui pengujian getActiveAndCompletedStats_noCompleted_returnsHundredZero() untuk menggunakan assertThat Hamcrest, bukan assertEquals.
// REPLACE
assertEquals(result.completedTasksPercent, 0f)
assertEquals(result.activeTasksPercent, 100f)

// WITH
assertThat(result.activeTasksPercent, `is`(100f))
assertThat(result.completedTasksPercent, `is`(0f))

Perhatikan bahwa Anda dapat menggunakan impor import org.hamcrest.Matchers.`is` jika diminta.

Pengujian akhir akan terlihat seperti kode di bawah.

StatisticsUtilsTest.kt

import com.example.android.architecture.blueprints.todoapp.data.Task
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.`is`
import org.junit.Test

class StatisticsUtilsTest {

    @Test
    fun getActiveAndCompletedStats_noCompleted_returnsHundredZero {

        // Create an active tasks (the false makes this active)
        val tasks = listOf<Task>(
            Task("title", "desc", isCompleted = false)
        )
        // Call your function
        val result = getActiveAndCompletedStats(tasks)

        // Check the result
        assertThat(result.activeTasksPercent, `is`(100f))
        assertThat(result.completedTasksPercent, `is`(0f))

    }
}
  1. Jalankan pengujian yang telah diupdate untuk mengonfirmasi bahwa pengujian masih berfungsi.

Codelab ini tidak akan mengajarkan semua seluk-beluk Hamcrest, jadi jika Anda ingin mempelajari lebih lanjut, lihat tutorial resmi.

Ini adalah tugas opsional untuk latihan.

Dalam tugas ini, Anda akan menulis lebih banyak pengujian menggunakan JUnit dan Hamcrest. Anda juga akan menulis pengujian menggunakan strategi yang berasal dari praktik program Pengembangan yang Didorong Pengujian. Pengembangan Berdasarkan Pengujian atau TDD adalah pemikiran pemrograman yang menyatakan bahwa alih-alih menulis kode fitur terlebih dahulu, Anda menulis pengujian terlebih dahulu. Kemudian, Anda menulis kode fitur dengan tujuan untuk lulus pengujian.

Langkah 1. Menulis pengujian

Menulis pengujian saat Anda memiliki daftar tugas normal:

  1. Jika ada satu tugas yang selesai dan tidak ada tugas yang aktif, persentase activeTasks harus 0f, dan persentase tugas yang selesai harus 100f .
  2. Jika ada dua tugas yang selesai dan tiga tugas yang aktif, persentase tugas yang selesai adalah 40f dan persentase tugas yang aktif adalah 60f.

Langkah 2. Menulis pengujian untuk bug

Kode untuk getActiveAndCompletedStats seperti yang ditulis memiliki bug. Perhatikan bagaimana fungsi ini tidak menangani dengan benar apa yang terjadi jika daftar kosong atau null. Dalam kedua kasus ini, kedua persentase harus nol.

internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {

   val totalTasks = tasks!!.size
   val numberOfActiveTasks = tasks.count { it.isActive }
   val activePercent = 100 * numberOfActiveTasks / totalTasks
   val completePercent = 100 * (totalTasks - numberOfActiveTasks) / totalTasks

   return StatsResult(
       activeTasksPercent = activePercent.toFloat(),
       completedTasksPercent = completePercent.toFloat()
   )
  
}

Untuk memperbaiki kode dan menulis pengujian, Anda akan menggunakan pengembangan berbasis pengujian. Pengembangan Berbasis Pengujian mengikuti langkah-langkah berikut.

  1. Tulis pengujian, menggunakan struktur Given, When, Then, dan dengan nama yang mengikuti konvensi.
  2. Pastikan pengujian gagal.
  3. Tulis kode minimal untuk membuat pengujian lulus.
  4. Ulangi untuk semua pengujian.

Daripada memulai dengan memperbaiki bug, Anda akan memulai dengan menulis pengujian terlebih dahulu. Kemudian, Anda dapat mengonfirmasi bahwa Anda memiliki pengujian yang melindungi Anda dari pengenalan kembali bug ini secara tidak sengaja di masa mendatang.

  1. Jika ada daftar kosong (emptyList()), kedua persentase harus 0f.
  2. Jika terjadi error saat memuat tugas, daftar akan menjadi null, dan kedua persentase harus 0f.
  3. Jalankan pengujian dan konfirmasi bahwa pengujian gagal:

Langkah 3. Memperbaiki bug

Setelah Anda memiliki pengujian, perbaiki bug.

  1. Perbaiki bug di getActiveAndCompletedStats dengan menampilkan 0f jika tasks adalah null atau kosong:
internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {

    return if (tasks == null || tasks.isEmpty()) {
        StatsResult(0f, 0f)
    } else {
        val totalTasks = tasks.size
        val numberOfActiveTasks = tasks.count { it.isActive }
        StatsResult(
            activeTasksPercent = 100f * numberOfActiveTasks / tasks.size,
            completedTasksPercent = 100f * (totalTasks - numberOfActiveTasks) / tasks.size
        )
    }
}
  1. Jalankan pengujian Anda lagi dan pastikan semua pengujian sekarang berhasil.

Dengan mengikuti TDD dan menulis pengujian terlebih dahulu, Anda telah membantu memastikan bahwa:

  • Fungsi baru selalu memiliki pengujian terkait; sehingga pengujian Anda berfungsi sebagai dokumentasi tentang fungsi kode Anda.
  • Pengujian Anda memeriksa hasil yang benar dan melindungi dari bug yang telah Anda lihat.

Solusi: Menulis lebih banyak pengujian

Berikut adalah semua pengujian dan kode fitur yang sesuai.

StatisticsUtilsTest.kt

class StatisticsUtilsTest {

    @Test
    fun getActiveAndCompletedStats_noCompleted_returnsHundredZero {
        val tasks = listOf(
            Task("title", "desc", isCompleted = false)
        )
        // When the list of tasks is computed with an active task
        val result = getActiveAndCompletedStats(tasks)

        // Then the percentages are 100 and 0
        assertThat(result.activeTasksPercent, `is`(100f))
        assertThat(result.completedTasksPercent, `is`(0f))
    }

    @Test
    fun getActiveAndCompletedStats_noActive_returnsZeroHundred() {
        val tasks = listOf(
            Task("title", "desc", isCompleted = true)
        )
        // When the list of tasks is computed with a completed task
        val result = getActiveAndCompletedStats(tasks)

        // Then the percentages are 0 and 100
        assertThat(result.activeTasksPercent, `is`(0f))
        assertThat(result.completedTasksPercent, `is`(100f))
    }

    @Test
    fun getActiveAndCompletedStats_both_returnsFortySixty() {
        // Given 3 completed tasks and 2 active tasks
        val tasks = listOf(
            Task("title", "desc", isCompleted = true),
            Task("title", "desc", isCompleted = true),
            Task("title", "desc", isCompleted = true),
            Task("title", "desc", isCompleted = false),
            Task("title", "desc", isCompleted = false)
        )
        // When the list of tasks is computed
        val result = getActiveAndCompletedStats(tasks)

        // Then the result is 40-60
        assertThat(result.activeTasksPercent, `is`(40f))
        assertThat(result.completedTasksPercent, `is`(60f))
    }

    @Test
    fun getActiveAndCompletedStats_error_returnsZeros() {
        // When there's an error loading stats
        val result = getActiveAndCompletedStats(null)

        // Both active and completed tasks are 0
        assertThat(result.activeTasksPercent, `is`(0f))
        assertThat(result.completedTasksPercent, `is`(0f))
    }

    @Test
    fun getActiveAndCompletedStats_empty_returnsZeros() {
        // When there are no tasks
        val result = getActiveAndCompletedStats(emptyList())

        // Both active and completed tasks are 0
        assertThat(result.activeTasksPercent, `is`(0f))
        assertThat(result.completedTasksPercent, `is`(0f))
    }
}

StatisticsUtils.kt

internal fun getActiveAndCompletedStats(tasks: List<Task>?): StatsResult {

    return if (tasks == null || tasks.isEmpty()) {
        StatsResult(0f, 0f)
    } else {
        val totalTasks = tasks.size
        val numberOfActiveTasks = tasks.count { it.isActive }
        StatsResult(
            activeTasksPercent = 100f * numberOfActiveTasks / tasks.size,
            completedTasksPercent = 100f * (totalTasks - numberOfActiveTasks) / tasks.size
        )
    }
}

Selamat, Anda telah mempelajari dasar-dasar penulisan dan menjalankan pengujian. Selanjutnya, Anda akan mempelajari cara menulis pengujian ViewModel dan LiveData dasar.

Di bagian codelab lainnya, Anda akan mempelajari cara menulis pengujian untuk dua class Android yang umum di sebagian besar aplikasi—ViewModel dan LiveData.

Anda mulai dengan menulis pengujian untuk TasksViewModel.


Anda akan berfokus pada pengujian yang memiliki semua logikanya dalam model tampilan dan tidak bergantung pada kode repositori. Kode repositori melibatkan kode asinkron, database, dan panggilan jaringan, yang semuanya menambah kompleksitas pengujian. Anda akan menghindarinya untuk saat ini dan berfokus pada penulisan pengujian untuk fungsi ViewModel yang tidak secara langsung menguji apa pun di repositori.



Pengujian yang akan Anda tulis akan memeriksa bahwa saat Anda memanggil metode addNewTask, Event untuk membuka jendela tugas baru akan diaktifkan. Berikut kode aplikasi yang akan Anda uji.

TasksViewModel.kt

fun addNewTask() {
   _newTaskEvent.value = Event(Unit)
}

Langkah 1. Buat class TasksViewModelTest

Dengan mengikuti langkah-langkah yang sama seperti yang Anda lakukan untuk StatisticsUtilTest, pada langkah ini, Anda akan membuat file pengujian untuk TasksViewModelTest.

  1. Buka class yang ingin Anda uji, dalam paket tasks, TasksViewModel.
  2. Di kode, klik kanan nama class TasksViewModel -> Generate -> Test.

  1. Di layar Create Test, klik OK untuk menerima (tidak perlu mengubah setelan default).
  2. Pada dialog Choose Destination Directory, pilih direktori test.

Langkah 2. Mulai Menulis Pengujian ViewModel

Pada langkah ini, Anda menambahkan pengujian model tampilan untuk menguji bahwa saat Anda memanggil metode addNewTask, Event untuk membuka jendela tugas baru akan dipicu.

  1. Buat pengujian baru bernama addNewTask_setsNewTaskEvent.

TasksViewModelTest.kt

class TasksViewModelTest {

    @Test
    fun addNewTask_setsNewTaskEvent() {

        // Given a fresh TasksViewModel


        // When adding a new task


        // Then the new task event is triggered

    }
    
}

Bagaimana dengan konteks aplikasi?

Saat Anda membuat instance TasksViewModel untuk diuji, konstruktornya memerlukan Konteks Aplikasi. Namun, dalam pengujian ini, Anda tidak membuat aplikasi lengkap dengan aktivitas, UI, dan fragmen, jadi bagaimana cara mendapatkan konteks aplikasi?

TasksViewModelTest.kt

// Given a fresh ViewModel
        val tasksViewModel = TasksViewModel(???)

Library Pengujian AndroidX mencakup class dan metode yang menyediakan versi komponen seperti Aplikasi dan Aktivitas yang ditujukan untuk pengujian. Jika Anda memiliki pengujian lokal yang memerlukan class framework Android simulasi (seperti Konteks Aplikasi), ikuti langkah-langkah berikut untuk menyiapkan AndroidX Test dengan benar:

  1. Tambahkan dependensi inti dan ext AndroidX Test
  2. Tambahkan dependensi Robolectric Testing library
  3. Memberi anotasi pada class dengan runner pengujian AndroidJunit4
  4. Menulis kode AndroidX Test

Anda akan menyelesaikan langkah-langkah ini dan kemudian memahami fungsi gabungannya.

Langkah 3. Menambahkan dependensi gradle

  1. Salin dependensi ini ke file build.gradle modul aplikasi Anda untuk menambahkan dependensi inti dan ext AndroidX Test, serta dependensi pengujian Robolectric.

app/build.gradle

    // AndroidX Test - JVM testing
testImplementation "androidx.test.ext:junit-ktx:$androidXTestExtKotlinRunnerVersion"

    testImplementation "androidx.test:core-ktx:$androidXTestCoreVersion"

 testImplementation "org.robolectric:robolectric:$robolectricVersion"

Langkah 4. Menambahkan Peluncur Pengujian JUnit

  1. Tambahkan @RunWith(AndroidJUnit4::class) di atas class pengujian Anda.

TasksViewModelTest.kt

@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {
    // Test code
}

Langkah 5. Menggunakan AndroidX Test

Pada tahap ini, Anda dapat menggunakan library AndroidX Test. Hal ini mencakup metode ApplicationProvider.getApplicationContext, yang mendapatkan Konteks Aplikasi.

  1. Buat TasksViewModel menggunakan ApplicationProvider.getApplicationContext()dari library pengujian AndroidX.

TasksViewModelTest.kt

// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
  1. Panggil addNewTask di tasksViewModel.

TasksViewModelTest.kt

tasksViewModel.addNewTask()

Pada tahap ini, pengujian Anda akan terlihat seperti kode di bawah.

TasksViewModelTest.kt

    @Test
    fun addNewTask_setsNewTaskEvent() {

        // Given a fresh ViewModel
        val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

        // When adding a new task
        tasksViewModel.addNewTask()

        // Then the new task event is triggered
        // TODO test LiveData
    }
  1. Jalankan pengujian untuk mengonfirmasi bahwa pengujian berfungsi.

Konsep: Bagaimana cara kerja AndroidX Test?

Apa itu AndroidX Test?

AndroidX Test adalah kumpulan library untuk pengujian. Library ini mencakup class dan metode yang memberi Anda versi komponen seperti Aplikasi dan Aktivitas, yang ditujukan untuk pengujian. Sebagai contoh, kode yang Anda tulis ini adalah contoh fungsi AndroidX Test untuk mendapatkan konteks aplikasi.

ApplicationProvider.getApplicationContext()

Salah satu manfaat AndroidX Test API adalah API ini dibuat untuk berfungsi baik untuk pengujian lokal maupun pengujian berinstrumen. Hal ini bagus karena:

  • Anda dapat menjalankan pengujian yang sama sebagai pengujian lokal atau pengujian berinstrumen.
  • Anda tidak perlu mempelajari berbagai API pengujian untuk pengujian lokal vs. pengujian berinstrumen.

Misalnya, karena Anda menulis kode menggunakan library AndroidX Test, Anda dapat memindahkan class TasksViewModelTest dari folder test ke folder androidTest dan pengujian akan tetap berjalan. getApplicationContext() berfungsi sedikit berbeda, bergantung pada apakah dijalankan sebagai pengujian lokal atau instrumentasi:

  • Jika merupakan pengujian yang diinstrumentasi, pengujian akan mendapatkan konteks Aplikasi sebenarnya yang diberikan saat mem-boot emulator atau terhubung ke perangkat sebenarnya.
  • Jika pengujiannya adalah pengujian lokal, lingkungan Android yang disimulasikan akan digunakan.

Apa itu Robolectric?

Lingkungan Android simulasi yang digunakan AndroidX Test untuk pengujian lokal disediakan oleh Robolectric. Robolectric adalah library yang membuat lingkungan Android simulasi untuk pengujian dan berjalan lebih cepat daripada mem-boot emulator atau berjalan di perangkat. Tanpa dependensi Robolectric, Anda akan mendapatkan error ini:

Apa fungsi @RunWith(AndroidJUnit4::class)?

Test runner adalah komponen JUnit yang menjalankan pengujian. Tanpa pelaksana pengujian, pengujian Anda tidak akan berjalan. Ada runner pengujian default yang disediakan oleh JUnit yang Anda dapatkan secara otomatis. @RunWith menggantikan runner pengujian default tersebut.

Runner pengujian AndroidJUnit4 memungkinkan AndroidX Test menjalankan pengujian Anda secara berbeda, bergantung pada apakah pengujian tersebut merupakan pengujian berinstrumen atau lokal.

Langkah 6. Memperbaiki Peringatan Robolectric

Saat Anda menjalankan kode, perhatikan bahwa Robolectric digunakan.

Berkat AndroidX Test dan peluncur pengujian AndroidJunit4, hal ini dilakukan tanpa Anda menulis satu baris kode Robolectric secara langsung.

Anda mungkin melihat dua peringatan.

  • No such manifest file: ./AndroidManifest.xml
  • "WARN: Android SDK 29 requires Java 9..."

Anda dapat memperbaiki peringatan No such manifest file: ./AndroidManifest.xml dengan memperbarui file gradle.

  1. Tambahkan baris berikut ke file gradle Anda agar manifes Android yang benar digunakan. Opsi includeAndroidResources memungkinkan Anda mengakses resource Android dalam pengujian unit, termasuk file AndroidManifest.

app/build.gradle

    // Always show the result of every unit test when running via command line, even if it passes.
    testOptions.unitTests {
        includeAndroidResources = true

        // ... 
    }

Peringatan "WARN: Android SDK 29 requires Java 9..." lebih rumit. Menjalankan pengujian di Android Q memerlukan Java 9. Daripada mencoba mengonfigurasi Android Studio untuk menggunakan Java 9, untuk codelab ini, pertahankan SDK target dan kompilasi Anda di 28.

Singkatnya:

  • Pengujian model tampilan murni biasanya dapat dilakukan di set sumber test karena kodenya biasanya tidak memerlukan Android.
  • Anda dapat menggunakan library pengujian AndroidX untuk mendapatkan versi pengujian komponen seperti Aplikasi dan Aktivitas.
  • Jika perlu menjalankan kode Android simulasi dalam set sumber test, Anda dapat menambahkan dependensi Robolectric dan anotasi @RunWith(AndroidJUnit4::class).

Selamat, Anda menggunakan library pengujian AndroidX dan Robolectric untuk menjalankan pengujian. Pengujian Anda belum selesai (Anda belum menulis pernyataan assert, hanya mengatakan // TODO test LiveData). Anda akan mempelajari cara menulis pernyataan assert dengan LiveData berikutnya.

Dalam tugas ini, Anda akan mempelajari cara menegaskan nilai LiveData dengan benar.

Berikut bagian yang terakhir Anda tonton tanpa pengujian model tampilan addNewTask_setsNewTaskEvent.

TasksViewModelTest.kt

    @Test
    fun addNewTask_setsNewTaskEvent() {

        // Given a fresh ViewModel
        val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

        // When adding a new task
        tasksViewModel.addNewTask()

        // Then the new task event is triggered
        // TODO test LiveData
    }
    

Untuk menguji LiveData, sebaiknya Anda melakukan dua hal:

  1. Gunakan InstantTaskExecutorRule
  2. Memastikan pengamatan LiveData

Langkah 1. Menggunakan InstantTaskExecutorRule

InstantTaskExecutorRule adalah Aturan JUnit. Saat Anda menggunakannya dengan anotasi @get:Rule, beberapa kode di class InstantTaskExecutorRule akan dijalankan sebelum dan setelah pengujian (untuk melihat kode persisnya, Anda dapat menggunakan pintasan keyboard Command+B untuk melihat file).

Aturan ini menjalankan semua tugas latar belakang terkait Komponen Arsitektur di thread yang sama sehingga hasil pengujian terjadi secara serentak, dan dalam urutan yang dapat diulang. Saat Anda menulis pengujian yang mencakup pengujian LiveData, gunakan aturan ini.

  1. Tambahkan dependensi gradle untuk library pengujian inti Komponen Arsitektur (yang berisi aturan ini).

app/build.gradle

testImplementation "androidx.arch.core:core-testing:$archTestingVersion"
  1. Buka TasksViewModelTest.kt
  2. Tambahkan InstantTaskExecutorRule di dalam class TasksViewModelTest.

TasksViewModelTest.kt

class TasksViewModelTest {
    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()
    
    // Other code...
}

Langkah 2. Menambahkan Class LiveDataTestUtil.kt

Langkah berikutnya adalah memastikan LiveData yang Anda uji diamati.

Saat menggunakan LiveData, Anda biasanya memiliki aktivitas atau fragmen (LifecycleOwner) yang mengamati LiveData.

viewModel.resultLiveData.observe(fragment, Observer {
    // Observer code here
})

Pengamatan ini penting. Anda memerlukan pengamat aktif di LiveData untuk

Untuk mendapatkan perilaku LiveData yang diharapkan untuk LiveData model tampilan, Anda perlu mengamati LiveData dengan LifecycleOwner.

Hal ini menimbulkan masalah: dalam pengujian TasksViewModel, Anda tidak memiliki aktivitas atau fragmen untuk mengamati LiveData. Untuk mengatasi hal ini, Anda dapat menggunakan metode observeForever, yang memastikan LiveData terus diamati, tanpa memerlukan LifecycleOwner. Saat Anda observeForever, Anda harus ingat untuk menghapus observer atau berisiko mengalami kebocoran observer.

Tampilannya akan terlihat seperti kode di bawah. Periksa:

@Test
fun addNewTask_setsNewTaskEvent() {

    // Given a fresh ViewModel
    val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())


    // Create observer - no need for it to do anything!
    val observer = Observer<Event<Unit>> {}
    try {

        // Observe the LiveData forever
        tasksViewModel.newTaskEvent.observeForever(observer)

        // When adding a new task
        tasksViewModel.addNewTask()

        // Then the new task event is triggered
        val value = tasksViewModel.newTaskEvent.value
        assertThat(value?.getContentIfNotHandled(), (not(nullValue())))

    } finally {
        // Whatever happens, don't forget to remove the observer!
        tasksViewModel.newTaskEvent.removeObserver(observer)
    }
}

Ada banyak kode boilerplate untuk mengamati satu LiveData dalam pengujian. Ada beberapa cara untuk menghapus boilerplate ini. Anda akan membuat fungsi ekstensi yang disebut LiveDataTestUtil untuk menyederhanakan penambahan pengamat.

  1. Buat file Kotlin baru bernama LiveDataTestUtil.kt di set sumber test Anda.


  1. Salin dan tempel kode di bawah.

LiveDataTestUtil.kt

import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException


@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun <T> LiveData<T>.getOrAwaitValue(
    time: Long = 2,
    timeUnit: TimeUnit = TimeUnit.SECONDS,
    afterObserve: () -> Unit = {}
): T {
    var data: T? = null
    val latch = CountDownLatch(1)
    val observer = object : Observer<T> {
        override fun onChanged(o: T?) {
            data = o
            latch.countDown()
            this@getOrAwaitValue.removeObserver(this)
        }
    }
    this.observeForever(observer)

    try {
        afterObserve.invoke()

        // Don't wait indefinitely if the LiveData is not set.
        if (!latch.await(time, timeUnit)) {
            throw TimeoutException("LiveData value was never set.")
        }

    } finally {
        this.removeObserver(observer)
    }

    @Suppress("UNCHECKED_CAST")
    return data as T
}

Ini adalah metode yang cukup rumit. Fungsi ini membuat fungsi ekstensi Kotlin yang disebut getOrAwaitValue yang menambahkan pengamat, mendapatkan nilai LiveData, lalu membersihkan pengamat—pada dasarnya adalah versi singkat dan dapat digunakan kembali dari kode observeForever yang ditunjukkan di atas. Untuk penjelasan lengkap tentang kelas ini, lihat postingan blog ini.

Langkah 3. Gunakan getOrAwaitValue untuk menulis pernyataan

Pada langkah ini, Anda menggunakan metode getOrAwaitValue dan menulis pernyataan assert yang memeriksa apakah newTaskEvent dipicu.

  1. Dapatkan nilai LiveData untuk newTaskEvent menggunakan getOrAwaitValue.
val value = tasksViewModel.newTaskEvent.getOrAwaitValue()
  1. Menyatakan bahwa nilai tidak boleh null.
assertThat(value.getContentIfNotHandled(), (not(nullValue())))

Pengujian lengkap akan terlihat seperti kode di bawah.

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.example.android.architecture.blueprints.todoapp.getOrAwaitValue
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.not
import org.hamcrest.Matchers.nullValue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {

    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()


    @Test
    fun addNewTask_setsNewTaskEvent() {
        // Given a fresh ViewModel
        val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

        // When adding a new task
        tasksViewModel.addNewTask()

        // Then the new task event is triggered
        val value = tasksViewModel.newTaskEvent.getOrAwaitValue()

        assertThat(value.getContentIfNotHandled(), not(nullValue()))


    }

}
  1. Jalankan kode Anda dan lihat pengujian berhasil.

Sekarang setelah Anda melihat cara menulis pengujian, tulis pengujian Anda sendiri. Pada langkah ini, menggunakan keterampilan yang telah Anda pelajari, latih penulisan pengujian TasksViewModel lainnya.

Langkah 1. Menulis pengujian ViewModel Anda sendiri

Anda akan menulis setFilterAllTasks_tasksAddViewVisible(). Pengujian ini harus memeriksa apakah tombol Tambahkan tugas terlihat jika Anda telah menyetel jenis filter untuk menampilkan semua tugas.

  1. Dengan menggunakan addNewTask_setsNewTaskEvent() sebagai referensi, tulis pengujian di TasksViewModelTest yang disebut setFilterAllTasks_tasksAddViewVisible() yang menyetel mode pemfilteran ke ALL_TASKS dan menegaskan bahwa LiveData tasksAddViewVisible adalah true.


Gunakan kode di bawah untuk memulai.

TasksViewModelTest

    @Test
    fun setFilterAllTasks_tasksAddViewVisible() {

        // Given a fresh ViewModel

        // When the filter type is ALL_TASKS

        // Then the "Add task" action is visible
        
    }

Catatan:

  • Enum TasksFilterType untuk semua tugas adalah ALL_TASKS.
  • Visibilitas tombol untuk menambahkan tugas dikontrol oleh LiveData tasksAddViewVisible.
  1. Jalankan pengujian.

Langkah 2. Bandingkan tes Anda dengan solusi

Bandingkan solusi Anda dengan solusi di bawah ini.

TasksViewModelTest

    @Test
    fun setFilterAllTasks_tasksAddViewVisible() {

        // Given a fresh ViewModel
        val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

        // When the filter type is ALL_TASKS
        tasksViewModel.setFiltering(TasksFilterType.ALL_TASKS)

        // Then the "Add task" action is visible
        assertThat(tasksViewModel.tasksAddViewVisible.getOrAwaitValue(), `is`(true))
    }

Periksa apakah Anda melakukan hal berikut:

  • Anda membuat tasksViewModel menggunakan pernyataan ApplicationProvider.getApplicationContext() AndroidX yang sama.
  • Anda memanggil metode setFiltering, dengan meneruskan enum jenis filter ALL_TASKS.
  • Anda memeriksa apakah tasksAddViewVisible benar, menggunakan metode getOrAwaitNextValue.

Langkah 3. Menambahkan aturan @Before

Perhatikan bagaimana di awal kedua pengujian, Anda menentukan TasksViewModel.

TasksViewModelTest

        // Given a fresh ViewModel
        val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

Jika memiliki kode penyiapan berulang untuk beberapa pengujian, Anda dapat menggunakan anotasi @Before untuk membuat metode penyiapan dan menghapus kode berulang. Karena semua pengujian ini akan menguji TasksViewModel, dan memerlukan model tampilan, pindahkan kode ini ke blok @Before.

  1. Buat variabel instance lateinit bernama tasksViewModel|.
  2. Buat metode yang disebut setupViewModel.
  3. Anotasikan dengan @Before.
  4. Pindahkan kode instansiasi model tampilan ke setupViewModel.

TasksViewModelTest

    // Subject under test
    private lateinit var tasksViewModel: TasksViewModel

    @Before
    fun setupViewModel() {
        tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
    }
  1. Jalankan kode!

Peringatan

Jangan lakukan hal berikut, jangan lakukan inisialisasi

tasksViewModel

dengan definisinya:

val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

Hal ini akan menyebabkan instance yang sama digunakan untuk semua pengujian. Hal ini harus dihindari karena setiap pengujian harus memiliki instance baru dari subjek yang sedang diuji (ViewModel dalam kasus ini).

Kode akhir Anda untuk TasksViewModelTest akan terlihat seperti kode di bawah.

TasksViewModelTest

@RunWith(AndroidJUnit4::class)
class TasksViewModelTest {

    // Subject under test
    private lateinit var tasksViewModel: TasksViewModel

    // Executes each task synchronously using Architecture Components.
    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    @Before
    fun setupViewModel() {
        tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
    }


    @Test
    fun addNewTask_setsNewTaskEvent() {

        // When adding a new task
        tasksViewModel.addNewTask()

        // Then the new task event is triggered
        val value = tasksViewModel.newTaskEvent.awaitNextValue()
        assertThat(
            value?.getContentIfNotHandled(), (not(nullValue()))
        )
    }

    @Test
    fun getTasksAddViewVisible() {

        // When the filter type is ALL_TASKS
        tasksViewModel.setFiltering(TasksFilterType.ALL_TASKS)

        // Then the "Add task" action is visible
        assertThat(tasksViewModel.tasksAddViewVisible.awaitNextValue(), `is`(true))
    }
    
}

Klik di sini untuk melihat perbedaan antara kode yang Anda mulai dan kode akhir.

Untuk mendownload kode codelab yang sudah selesai, Anda dapat menggunakan perintah git di bawah:

$ git clone https://github.com/googlecodelabs/android-testing.git
$ cd android-testing
$ git checkout end_codelab_1


Atau, Anda dapat mendownload repositori sebagai file ZIP, mengekstraknya, dan membukanya di Android Studio.

Download Zip

Codelab ini mencakup:

  • Cara menjalankan pengujian dari Android Studio.
  • Perbedaan antara pengujian lokal (test) dan uji instrumentasi (androidTest).
  • Cara menulis pengujian unit lokal menggunakan JUnit dan Hamcrest.
  • Menyiapkan pengujian ViewModel dengan AndroidX Test Library.

Kursus Udacity:

Dokumentasi developer Android:

Video:

Lainnya:

Untuk mengetahui link ke codelab lain dalam kursus ini, lihat halaman landing codelab Android Lanjutan di Kotlin.