Dasar-Dasar Pengujian

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

Pengantar

Saat menerapkan fitur pertama pada aplikasi pertama, Anda mungkin menjalankan kode untuk memverifikasi bahwa aplikasi berfungsi seperti yang diharapkan. Anda telah melakukan pengujian, meskipun pengujian manual dilakukan. Seiring Anda terus menambahkan dan mengupdate fitur, Anda mungkin juga terus menjalankan kode dan memverifikasi bahwa kode tersebut berfungsi. Namun, melakukannya secara manual setiap kali memang melelahkan, rentan kesalahan, dan tidak menyesuaikan skala.

Komputer sangat bagus untuk 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 bahwa kode berfungsi.

Yang akan Anda pelajari dalam rangkaian 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 Berdasarkan Pengujian
  • Cara memilih uji instrumentasi dan pengujian lokal

Anda akan mempelajari library 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 Matcher.
  • Tulis pengujian LiveData dan ViewModel sederhana.

Dalam serangkaian codelab ini, Anda akan mengerjakan aplikasi Catatan TO-DO. Aplikasi ini memungkinkan Anda menulis tugas untuk diselesaikan dan menampilkannya dalam daftar. Selanjutnya, Anda dapat menandainya sebagai selesai atau tidak, memfilter, atau menghapusnya.

Aplikasi ini ditulis dalam 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 contoh aplikasi

Setelah mendownload aplikasi Daftar Tugas, buka aplikasi di Android Studio dan jalankan. Kode harus dikompilasi. Jelajahi aplikasi dengan melakukan hal berikut:

  • Buat tugas baru dengan tombol plus tindakan mengambang. 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 menetapkan statusnya menjadi Selesai.
  • Kembali ke layar tugas, buka menu filter, dan filter tugas berdasarkan status Aktif dan Selesai.
  • Buka panel navigasi dan 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 Daftar Tugas didasarkan pada contoh pengujian dan arsitektur Arsitektur Biru yang populer (menggunakan versi arsitektur reaktif dari contoh). Aplikasi mengikuti arsitektur dari Panduan arsitektur aplikasi. Menggunakan ViewModels dengan Fragment, repositori, dan Room. Jika Anda terbiasa dengan salah satu contoh di bawah, aplikasi ini memiliki arsitektur yang serupa:

Anda harus memahami arsitektur umum aplikasi daripada memiliki pemahaman mendalam tentang logika di satu lapisan.

Berikut ringkasan paket yang akan Anda temukan:

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

.addedittask

Menambahkan atau mengedit layar tugas: Kode lapisan UI untuk menambahkan atau mengedit tugas.

.data

Lapisan data: Hal ini berkaitan dengan lapisan data tugas. Project ini berisi database, jaringan, dan kode 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 geser ulang yang digunakan di beberapa layar.

Lapisan data (.data)

Aplikasi ini menyertakan lapisan jaringan yang disimulasikan, dalam paket jarak jauh, dan lapisan database, dalam paket lokal. Untuk mempermudah, dalam project ini lapisan jaringan disimulasikan hanya dengan HashMap dengan penundaan, daripada membuat permintaan jaringan yang sebenarnya.

Koordinat DefaultTasksRepository atau memediasi antara lapisan jaringan dan lapisan database serta merupakan yang mengembalikan data ke lapisan UI.

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

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

Navigasi

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

Dalam tugas ini, Anda akan menjalankan pengujian pertama.

  1. Di Android Studio, buka panel Project, lalu cari tiga folder berikut:
  • com.example.android.architecture.blueprints.todoapp
  • com.example.android.architecture.blueprints.todoapp (androidTest)
  • com.example.android.architecture.blueprints.todoapp (test)

Folder ini dikenal sebagai set sumber. Set sumber adalah folder yang berisi kode sumber untuk aplikasi Anda. Set 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 dibagikan di antara semua versi aplikasi lain 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 menjalankannya.

Pengujian lokal (test set sumber)

Pengujian ini dijalankan secara lokal di JVM mesin pengembangan dan tidak memerlukan emulator atau perangkat fisik. Oleh karena itu, iklan tersebut berjalan cepat, tetapi fidelitasnya lebih rendah, yang artinya mereka tidak banyak bertindak seperti di dunia nyata.

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

Pengujian berinstrumen (androidTest set sumber)

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

Dalam pengujian berinstrumen Android Studio, hal ini ditunjukkan dengan Android dengan ikon segitiga hijau dan merah.

Langkah 1: Jalankan pengujian lokal

  1. Buka folder test sampai Anda menemukan file ExampleUnitTest.kt.
  2. Klik kanan ruang ini lalu pilih Run ExampleUnitTest.

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

  1. Perhatikan tanda centang hijau dan perluas hasil pengujian untuk mengonfirmasi bahwa satu pengujian bernama addition_isCorrect lulus. Ada baiknya 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 pengujian tunggal).
  • biasanya berisi pernyataan pernyataan.

Android menggunakan library pengujian JUnit untuk pengujian (dalam codelab ini JUnit4). Baik pernyataan maupun anotasi @Test berasal dari JUnit.

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

Untuk melihat seperti apa pengujian yang gagal, tambahkan pernyataan yang dapat Anda lihat dengan mudah akan gagal. Ini akan memeriksa bahwa 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. Pada hasil pengujian, perhatikan X di samping pengujian.

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

Langkah 3: Jalankan uji instrumentasi

Pengujian berinstrumen ada dalam set sumber androidTest.

  1. Buka set sumber androidTest.
  2. Jalankan pengujian bernama 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 pada perangkat (dalam contoh di bawah ponsel Pixel 2 yang diemulasikan):

Jika Anda memiliki perangkat yang terpasang atau emulator yang berjalan, Anda akan melihat pengujian berjalan pada emulator.

Dalam tugas ini, Anda akan menulis pengujian untuk getActiveAndCompleteStats, yang menghitung persentase statistik tugas aktif dan lengkap 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.

StatistikUtils.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 yang aktif.

Android Studio menyediakan alat untuk menghasilkan stub pengujian guna membantu Anda menerapkan pengujian untuk fungsi ini.

  1. Klik kanan getActiveAndCompletedStats dan pilih Buat > Uji.

Dialog Create Test akan terbuka:

  1. Ubah Class name: menjadi StatisticsUtilsTest (bukan StatisticsUtilsKtTest; sebaiknya jangan sertakan KT pada 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 apa pun (ini hanya menghasilkan kode tambahan, tetapi Anda akan menulis pengujian dari awal).
  3. Tekan Oke

Dialog Choose Destination Directory akan terbuka:

Anda akan membuat tes lokal karena fungsi Anda melakukan perhitungan matematika dan tidak akan menyertakan kode khusus Android apa pun. Jadi, Anda tidak perlu menjalankannya di perangkat sungguhan atau yang diemulasikan.

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

Langkah 2: Tulis fungsi pengujian pertama Anda

Anda akan menulis pengujian yang memeriksa:

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

StatistikUtilsTest.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 itu adalah pengujian.
  2. Membuat 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 harapan Anda menggunakan pernyataan.
// Check the result
assertEquals(result.completedTasksPercent, 0f)
assertEquals(result.activeTasksPercent, 100f)

Kode lengkapnya sebagai berikut.

StatistikUtilsTest.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).

Kode tersebut harus lulus:

Langkah 3: Tambahkan dependensi AdID

Karena pengujian Anda bertindak sebagai dokumentasi tentang apa yang dilakukan kode Anda, sebaiknya lakukan pengujian yang dapat dibaca manusia. Bandingkan dua pernyataan berikut:

assertEquals(result.completedTasksPercent, 0f)

// versus

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

Pernyataan kedua membaca lebih seperti kalimat manusia. Ini ditulis menggunakan framework pernyataan yang disebut targetSdkVersion. Alat bagus lainnya untuk menulis pernyataan yang dapat dibaca adalah library Truth. Anda akan menggunakan targetSdkVersion 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 membuat ukuran APK menjadi terlalu besar dengan kode pengujian atau dependensi apa pun dalam aplikasi Anda. Anda dapat menetapkan 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 dalam set sumber pengujian.
  • androidTestImplementation—Dependensi hanya tersedia dalam set sumber androidTest.

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

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

Artinya, AdID hanya akan tersedia di set sumber pengujian. Ini juga memastikan bahwa targetSdkVersion tidak akan disertakan dalam aplikasi final Anda.

Langkah 4: Gunakan targetSdkVersion untuk menulis pernyataan

  1. Perbarui pengujian getActiveAndCompletedStats_noCompleted_returnsHundredZero() untuk menggunakan assertThat AdID, 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 terakhir akan terlihat seperti kode di bawah ini.

StatistikUtilsTest.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 diperbarui untuk mengonfirmasi bahwa pengujian masih berfungsi.

Codelab ini tidak akan mengajarkan semua seluk-beluk targetSdkVersion, 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 targetSdkVersion. Anda juga akan menulis pengujian menggunakan strategi yang berasal dari praktik program Pengembangan Berdasarkan Pengujian. Pengujian Berdasarkan Pengembangan atau TDD adalah sekolah pemikiran pemrograman yang mengatakan 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 telah selesai dan tidak ada tugas aktif, persentase activeTasks harus 0f, dan persentase tugas yang diselesaikan harus 100f .
  2. Jika ada dua tugas yang telah selesai dan tiga tugas aktif, persentase yang diselesaikan harus 40f dan persentase aktif harus 60f.

Langkah 2. Menulis pengujian untuk bug

Kode untuk getActiveAndCompletedStats seperti yang ditulis memiliki bug. Perhatikan bahwa kode 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 harus menggunakan pengembangan yang didorong oleh pengujian. Pengembangan Berdasarkan Pengujian mengikuti langkah-langkah berikut.

  1. Tulis pengujian, menggunakan struktur yang ditentukan, Kapan, Kemudian, dan dengan nama yang mengikuti konvensi.
  2. Konfirmasi bahwa pengujian gagal.
  3. Tulis kode minimal agar pengujian lulus.
  4. Ulangi untuk semua pengujian!

Alih-alih memulai dengan memperbaiki bug, Anda akan memulai dengan menulis pengujian terlebih dahulu. Selanjutnya, Anda dapat mengonfirmasi bahwa ada pengujian yang melindungi Anda dari bug yang tidak sengaja diperkenalkan kembali di masa mendatang.

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

Langkah 3. Memperbaiki bug

Setelah menjalankan pengujian, perbaiki bug tersebut.

  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 lagi dan konfirmasikan bahwa 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 bertindak sebagai dokumentasi tentang apa yang dilakukan kode Anda.
  • Pengujian Anda memeriksa hasil yang benar dan melindungi dari bug yang telah Anda lihat.

Solusi: Menulis pengujian lainnya

Berikut adalah semua pengujian dan kode fitur yang sesuai.

StatistikUtilsTest.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))
    }
}

StatistikUtils.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
        )
    }
}

Kerja yang bagus dengan dasar-dasar menulis dan menjalankan pengujian. Berikutnya, Anda akan mempelajari cara menulis pengujian dasar ViewModel dan LiveData.

Di 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 logika logika dalam model tampilan dan tidak mengandalkan kode repositori. Kode repositori melibatkan kode asinkron, database, dan panggilan jaringan, yang semuanya menambah kerumitan pengujian. Anda akan menghindarinya untuk saat ini dan berfokus pada penulisan pengujian untuk fungsi ViewModel yang tidak langsung menguji apa pun di repositori.



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

TasksViewModel.kt

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

Langkah 1. Membuat class TasksViewModelTest

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

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

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

Langkah 2. Mulai Menulis Pengujian ViewModel Anda

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

  1. Buat pengujian baru yang disebut 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 serta UI dan fragmen, jadi bagaimana Anda mendapatkan konteks aplikasi?

TasksViewModelTest.kt

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

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

  1. Menambahkan dependensi core dan ext Pengujian AndroidX
  2. Menambahkan dependensi Robolectric Testing library
  3. Menganotasi class dengan runner pengujian AndroidJunit4
  4. Menulis kode Pengujian AndroidX

Anda akan menyelesaikan langkah-langkah ini dan kemudian memahami apa yang mereka lakukan bersama.

Langkah 3. Menambahkan dependensi Gradle

  1. Salin dependensi ini ke dalam file build.gradle modul aplikasi Anda untuk menambahkan dependensi inti dan ext inti 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 JUnit Test Runner

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

TasksViewModelTest.kt

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

Langkah 5. Menggunakan AndroidX Test

Pada tahap ini, Anda dapat menggunakan library AndroidX Test. 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. Hubungi 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. Ini mencakup class dan metode yang memberi Anda versi komponen seperti Aplikasi dan Aktivitas, yang dimaksudkan 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 dibuat untuk berfungsi baik untuk pengujian lokal dan pengujian berinstrumen. Ini bagus karena:

  • Anda dapat menjalankan pengujian yang sama dengan pengujian lokal maupun pengujian berinstrumen.
  • Anda tidak perlu mempelajari API pengujian yang berbeda untuk pengujian lokal vs. 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() bekerja dengan cara yang sedikit berbeda, bergantung pada apakah aplikasi tersebut dijalankan sebagai pengujian lokal atau berinstrumen:

  • Jika berupa pengujian berinstrumen, aplikasi akan mendapatkan konteks Aplikasi sebenarnya yang diberikan saat mem-boot emulator atau terhubung ke perangkat sebenarnya.
  • Jika merupakan pengujian lokal, pengujian ini menggunakan lingkungan Android simulasi.

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 melakukan booting emulator atau berjalan di perangkat. Tanpa dependensi Robolectric, Anda akan mendapatkan error ini:

Apa fungsi @RunWith(AndroidJUnit4::class)?

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

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

Langkah 6. Memperbaiki Peringatan Robolectric

Saat Anda menjalankan kode, perhatikan bahwa Robolectric digunakan.

Karena AndroidX Test dan runner 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 untuk menggunakan manifes Android yang benar. Opsi includeAndroidResources memungkinkan Anda mengakses resource Android dalam pengujian unit Anda, 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, simpan target Anda dan kompilasi SDK pada angka 28.

Ringkasan:

  • 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 uji komponen seperti Aplikasi dan Aktivitas.
  • Jika perlu menjalankan simulasi kode Android di set sumber test, Anda dapat menambahkan dependensi Robolectric dan anotasi @RunWith(AndroidJUnit4::class).

Selamat, Anda menggunakan library pengujian AndroidX dan Robolectric untuk menjalankan pengujian. Tes Anda belum selesai (Anda belum menulis pernyataan tegas, hanya tertulis // TODO test LiveData). Anda akan belajar menulis pernyataan tegas dengan LiveData selanjutnya.

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

Dari yang terakhir Anda lakukan tanpa melihat 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, Anda disarankan untuk 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 yang terkait Komponen Arsitektur dalam thread yang sama sehingga hasil pengujian terjadi secara sinkron, dan dalam urutan yang dapat diulang. Saat Anda menulis pengujian yang menyertakan 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 Anda berikutnya adalah memastikan LiveData pengujian yang Anda amati.

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 observer aktif di LiveData untuk

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

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 observeForever, Anda perlu ingat untuk menghapus pengamat atau berisiko kebocoran pengamat.

Ini 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)
    }
}

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 mempermudah penambahan observer.

  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 bernama getOrAwaitValue yang menambahkan observer, mendapatkan nilai LiveData, lalu membersihkan observer—pada dasarnya, versi singkat yang dapat digunakan kembali dari kode observeForever yang ditunjukkan di atas. Untuk penjelasan lengkap tentang kelas ini, lihat postingan blog ini.

Langkah 3. Menggunakan getOrAwaitValue untuk menulis pernyataan

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

  1. Dapatkan nilai LiveData untuk newTaskEvent menggunakan getOrAwaitValue.
val value = tasksViewModel.newTaskEvent.getOrAwaitValue()
  1. Nyatakan bahwa nilainya bukan null.
assertThat(value.getContentIfNotHandled(), (not(nullValue())))

Pengujian lengkap akan terlihat seperti kode di bawah ini.

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 dan tonton ujiannya.

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

Langkah 1. Menulis pengujian ViewModel Anda sendiri

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

  1. Dengan menggunakan addNewTask_setsNewTaskEvent() sebagai referensi, tulis pengujian dalam TasksViewModelTest yang disebut setFilterAllTasks_tasksAddViewVisible() yang menetapkan 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 Anda.

Langkah 2. Bandingkan pengujian Anda dengan solusinya

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 memastikan bahwa tasksAddViewVisible benar, menggunakan metode getOrAwaitNextValue.

Langkah 3. Tambahkan aturan @Before

Perhatikan bagaimana Anda menentukan TasksViewModel di awal kedua pengujian.

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 pembuatan instance model 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 melakukan inisialisasi

tasksViewModel

dengan definisinya:

val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

Tindakan ini akan menyebabkan instance yang sama digunakan untuk semua pengujian. Ini adalah hal yang harus Anda hindari karena setiap pengujian harus memiliki instance baru dari subjek yang sedang diuji (ViewModel dalam kasus ini).

Kode final untuk TasksViewModelTest akan terlihat seperti kode di bawah ini.

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 membahas:

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

Kursus Udacity:

Dokumentasi developer Android:

Video:

Lainnya:

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