Menguji Aplikasi Cupcake

1. Pengantar

Di codelab Menavigasi antarlayar dengan Compose, Anda telah mempelajari cara menambahkan navigasi ke aplikasi Compose menggunakan komponen Jetpack Navigation Compose.

Aplikasi Cupcake memiliki beberapa layar untuk dinavigasi dan berbagai tindakan yang dapat dilakukan pengguna. Aplikasi ini memberikan peluang besar untuk mengasah keterampilan pengujian otomatis Anda. Dalam codelab ini, Anda akan menulis sejumlah pengujian UI untuk aplikasi Cupcake dan mempelajari cara melakukan pendekatan untuk memaksimalkan cakupan pengujian.

Prasyarat

Yang akan Anda pelajari

  • Menguji komponen Jetpack Navigation dengan Compose.
  • Membuat status UI yang konsisten untuk setiap pengujian UI.
  • Membuat fungsi bantuan untuk pengujian.

Yang akan Anda bangun

  • Pengujian UI untuk aplikasi Cupcake

Yang Anda butuhkan

  • Versi terbaru Android Studio
  • Koneksi internet untuk mendownload kode awal

2. Mendownload kode awal

  1. Di Android Studio, buka folder basic-android-kotlin-compose-training-cupcake.
  2. Buka kode aplikasi Cupcake di Android Studio.

3. Menyiapkan Cupcake untuk pengujian UI

Menambahkan dependensi androidTest

Alat build Gradle memungkinkan Anda menambahkan dependensi untuk modul tertentu. Fungsi ini mencegah dependensi agar tidak dikompilasi. Anda sudah terbiasa dengan konfigurasi implementation saat menyertakan dependensi dalam sebuah project. Anda telah menggunakan kata kunci ini untuk mengimpor dependensi dalam file build.gradle.kts modul aplikasi. Menggunakan kata kunci implementation akan membuat dependensi tersebut tersedia untuk semua set sumber dalam modul tersebut; pada tahap ini, Anda telah mendapatkan pengalaman dengan set sumber main, test, dan androidTest.

Pengujian UI terdapat dalam set sumbernya sendiri yang disebut androidTest. Dependensi yang hanya diperlukan untuk modul ini tidak perlu dikompilasi untuk modul lain, seperti modul main, tempat kode aplikasi berada. Saat menambahkan dependensi yang hanya digunakan oleh pengujian UI, gunakan kata kunci androidTestImplementation untuk mendeklarasikan dependensi dalam file build.gradle.kts modul aplikasi. Tindakan ini akan memastikan bahwa dependensi pengujian UI dikompilasi hanya saat Anda menjalankan pengujian UI.

Selesaikan langkah-langkah berikut untuk menambahkan dependensi yang diperlukan untuk menulis pengujian UI:

  1. Buka file build.gradle.kts(Module :app).
  2. Tambahkan dependensi berikut ke bagian dependencies pada file:
androidTestImplementation(platform("androidx.compose:compose-bom:2023.05.01"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
androidTestImplementation("androidx.navigation:navigation-testing:2.6.0")
androidTestImplementation("androidx.test.espresso:espresso-intents:3.5.1")
androidTestImplementation("androidx.test.ext:junit:1.1.5")

Membuat direktori pengujian UI

  1. Klik kanan direktori src pada tampilan project lalu pilih New > Directory.

290b1ab99ce8f4e5.png

  1. Pilih opsi androidTest/java.

718bde5eb21b4f6f.png

Membuat paket pengujian

  1. Klik kanan direktori androidTest/java di jendela project, lalu pilih New > Package.

7ad315f41e2b0881.png

  1. Beri nama paket com.example.cupcake.test. b8306f9d11988a2.png

Membuat class pengujian navigasi

Di direktori test, buat class Kotlin baru bernama CupcakeScreenNavigationTest.

5515db35968f7d86.png

4b527e7404fad927.png

4. Menyiapkan host navigasi

Pada codelab sebelumnya, Anda telah mempelajari bahwa pengujian UI di Compose memerlukan aturan pengujian Compose. Hal yang sama berlaku untuk pengujian Jetpack Navigation. Namun, navigasi pengujian memerlukan beberapa penyiapan tambahan melalui aturan pengujian Compose.

Saat menguji Navigasi Compose, Anda tidak akan memiliki akses ke NavHostController yang sama dengan yang Anda lakukan di kode aplikasi. Namun, Anda dapat menggunakan TestNavHostController dan mengonfigurasi aturan pengujian dengan pengontrol navigasi ini. Di bagian ini, Anda akan mempelajari cara mengonfigurasi dan menggunakan kembali aturan pengujian untuk pengujian navigasi.

  1. Di CupcakeScreenNavigationTest.kt, buat aturan pengujian menggunakan createAndroidComposeRule dan teruskan ComponentActivity sebagai parameter jenis.
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import org.junit.Rule

@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()

Untuk memastikan aplikasi Anda menuju ke tempat yang benar, Anda perlu mereferensikan instance TestNavHostController untuk memeriksa rute navigasi host navigasi saat aplikasi mengambil tindakan untuk melakukan navigasi.

  1. Buat instance TestNavHostController sebagai variabel lateinit. Di Kotlin, kata kunci lateinit digunakan untuk mendeklarasikan properti yang dapat diinisialisasi setelah objek dideklarasikan.
import androidx.navigation.testing.TestNavHostController

private lateinit var navController: TestNavHostController

Berikutnya, tentukan composable yang ingin Anda gunakan untuk pengujian UI.

  1. Buat metode yang disebut setupCupcakeNavHost().
  2. Dalam metode setupCupcakeNavHost(), panggil metode setContent() pada aturan pengujian Compose yang Anda buat.
  3. Di dalam lambda yang diteruskan ke metode setContent(), panggil composable CupcakeApp().
import com.example.cupcake.CupcakeApp

fun setupCupcakeNavHost() {
    composeTestRule.setContent {
        CupcakeApp()
    }
}

Sekarang Anda perlu membuat objek TestNavHostContoller di class pengujian. Anda menggunakan objek ini nanti untuk menentukan status navigasi, karena aplikasi menggunakan pengontrol untuk menavigasi berbagai layar di aplikasi Cupcake.

  1. Siapkan host navigasi menggunakan lambda yang Anda buat sebelumnya. Lakukan inisialisasi pada variabel navController yang Anda buat, daftarkan navigator, lalu teruskan TestNavHostController tersebut ke composable CupcakeApp.
import androidx.compose.ui.platform.LocalContext

fun setupCupcakeNavHost() {
    composeTestRule.setContent {
        navController = TestNavHostController(LocalContext.current).apply {
            navigatorProvider.addNavigator(ComposeNavigator())
        }
        CupcakeApp(navController = navController)
    }
}

Setiap pengujian di class CupcakeScreenNavigationTest melibatkan pengujian aspek navigasi. Oleh karena itu, setiap pengujian bergantung pada objek TestNavHostController yang Anda buat. Daripada harus memanggil fungsi setupCupcakeNavHost() secara manual untuk setiap pengujian guna menyiapkan pengontrol nav, Anda dapat melakukannya secara otomatis menggunakan anotasi @Before yang disediakan oleh library junit. Jika metode dianotasi dengan @Before, metode tersebut akan berjalan sebelum setiap metode yang dianotasi dengan @Test.

  1. Tambahkan anotasi @Before ke metode setupCupcakeNavHost().
import org.junit.Before

@Before
fun setupCupcakeNavHost() {
    composeTestRule.setContent {
        navController = TestNavHostController(LocalContext.current).apply {
            navigatorProvider.addNavigator(ComposeNavigator())
        }
        CupcakeApp(navController = navController)
    }
}

5. Menulis pengujian navigasi

Memverifikasi tujuan awal

Ingat bahwa saat membangun aplikasi Cupcake, Anda membuat class enum bernama CupcakeScreen yang berisi konstanta untuk mendikte navigasi aplikasi.

CupcakeScreen.kt

/**
* enum values that represent the screens in the app
*/
enum class CupcakeScreen(@StringRes val title: Int) {
   Start(title = R.string.app_name),
   Flavor(title = R.string.choose_flavor),
   Pickup(title = R.string.choose_pickup_date),
   Summary(title = R.string.order_summary)
}

Semua aplikasi yang memiliki UI memiliki layar utama. Untuk Cupcake, layar tersebut adalah Layar Mulai Pesanan. Pengontrol navigasi dalam composable CupcakeApp menggunakan item Start dari enum CupcakeScreen untuk menentukan kapan harus membuka layar ini. Saat aplikasi dimulai, jika rute tujuan belum ada, rute tujuan host navigasi diatur ke CupcakeScreen.Start.name.

Anda harus menulis pengujian terlebih dahulu untuk memverifikasi bahwa Layar Mulai Pesanan adalah rute tujuan saat ini ketika aplikasi dimulai.

  1. Buat fungsi dengan nama cupcakeNavHost_verifyStartDestination() dan anotasikan dengan @Test.
import org.junit.Test

@Test
fun cupcakeNavHost_verifyStartDestination() {
}

Sekarang Anda harus mengonfirmasi bahwa rute tujuan awal pengontrol navigasi adalah Layar Mulai Pesanan.

  1. Nyatakan bahwa nama rute yang diharapkan (dalam hal ini, CupcakeScreen.Start.name) sama dengan rute tujuan entri data sebelumnya dari pengontrol navigasi saat ini.
import org.junit.Assert.assertEquals
...

@Test
fun cupcakeNavHost_verifyStartDestination() {
    assertEquals(CupcakeScreen.Start.name, navController.currentBackStackEntry?.destination?.route)
}

Membuat metode bantuan

Pengujian UI sering kali mengharuskan pengulangan langkah untuk menempatkan UI dalam status saat bagian UI tertentu dapat diuji. UI kustom juga dapat memerlukan pernyataan kompleks yang memerlukan beberapa baris kode. Pernyataan yang Anda tulis di bagian sebelumnya memerlukan banyak kode, dan Anda menggunakan pernyataan yang sama berkali-kali saat menguji navigasi di aplikasi Cupcake. Dalam situasi ini, menulis metode bantuan dalam pengujian menghindarkan Anda dari menulis kode duplikat.

Untuk setiap pengujian navigasi yang Anda tulis, Anda menggunakan properti name dari item enum CupcakeScreen untuk memeriksa apakah rute tujuan saat ini dari pengontrol navigasi sudah benar. Anda menulis fungsi bantuan yang dapat Anda panggil setiap kali Anda ingin membuat pernyataan tersebut.

Selesaikan langkah-langkah berikut untuk membuat fungsi bantuan ini:

  1. Buat file Kotlin kosong di direktori test bernama ScreenAssertions.

63af08bd78a827c4.png

  1. Tambahkan fungsi ekstensi ke class NavController yang disebut assertCurrentRouteName() dan teruskan string untuk nama rute yang diharapkan dalam tanda tangan metode.
fun NavController.assertCurrentRouteName(expectedRouteName: String) {

}
  1. Dalam fungsi ini, nyatakan bahwa expectedRouteName sama dengan rute tujuan entri data sebelumnya dari pengontrol navigasi saat ini.
import org.junit.Assert.assertEquals
...

fun NavController.assertCurrentRouteName(expectedRouteName: String) {
    assertEquals(expectedRouteName, currentBackStackEntry?.destination?.route)
}
  1. Buka file CupcakeScreenNavigationTest dan ubah fungsi cupcakeNavHost_verifyStartDestination() untuk menggunakan fungsi ekstensi baru Anda, bukan pernyataan yang panjang.
@Test
fun cupcakeNavHost_verifyStartDestination() {
    navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

Sejumlah pengujian juga memerlukan interaksi dengan komponen UI. Dalam codelab ini, komponen tersebut sering ditemukan menggunakan string resource. Anda dapat mengakses composable berdasarkan string resource-nya dengan metode Context.getString(), yang dapat Anda baca di sini. Saat menulis pengujian UI di Compose, menerapkan metode ini akan terlihat seperti ini:

composeTestRule.onNodeWithText(composeTestRule.activity.getString(R.string.my_string)

Ini adalah petunjuk panjang dan dapat disederhanakan dengan penambahan fungsi ekstensi.

  1. Buat file baru dalam paket com.example.cupcake.test bernama ComposeRuleExtensions.kt. Pastikan file ini adalah file Kotlin kosong.

5710fc2d8219048b.png

  1. Tambahkan kode berikut ke file tersebut.
import androidx.activity.ComponentActivity
import androidx.annotation.StringRes
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.onNodeWithText
import androidx.test.ext.junit.rules.ActivityScenarioRule

fun <A : ComponentActivity> AndroidComposeTestRule<ActivityScenarioRule<A>, A>.onNodeWithStringId(
    @StringRes id: Int
): SemanticsNodeInteraction = onNodeWithText(activity.getString(id))

Fungsi ekstensi ini memungkinkan Anda mengurangi jumlah kode yang Anda tulis saat menemukan komponen UI dengan resource string-nya. Daripada menulis ini:

composeTestRule.onNodeWithText(composeTestRule.activity.getString(R.string.my_string)

Sekarang Anda dapat menggunakan petunjuk berikut:

composeTestRule.onNodeWithStringId(R.string.my_string)

Memastikan layar Mulai tidak memiliki tombol Atas

Desain awal aplikasi Cupcake tidak memiliki tombol Up (Atas) di toolbar layar Mulai.

ffb8d156220c7e57.png

Layar Mulai tidak memiliki tombol karena tidak ada navigasi ke Atas (Up) dari layar ini, karena layar ini adalah layar awal. Ikuti langkah-langkah berikut untuk membuat fungsi yang mengonfirmasi bahwa layar Mulai tidak memiliki tombol Atas:

  1. Buat metode dengan nama cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() dan anotasikan dengan @Test.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
}

Di Cupcake, tombol Atas memiliki deskripsi konten yang diatur ke string dari resource R.string.back_button.

  1. Buat variabel dalam fungsi pengujian dengan nilai resource R.string.back_button.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
    val backText = composeTestRule.activity.getString(R.string.back_button)
}
  1. Nyatakan bahwa node dengan deskripsi konten ini tidak ada di layar.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
    val backText = composeTestRule.activity.getString(R.string.back_button)
    composeTestRule.onNodeWithContentDescription(backText).assertDoesNotExist()
}

Memverifikasi navigasi ke layar Rasa

Mengklik salah satu tombol di layar Mulai akan memicu metode yang menginstruksikan pengontrol navigasi untuk membuka layar Flavor (Rasa).

3bda045bfe202c90.png

Dalam pengujian ini, Anda akan menulis perintah untuk mengklik tombol guna memicu navigasi ini dan memverifikasi bahwa rute tujuannya adalah layar Flavor (Rasa).

  1. Buat fungsi dengan nama cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() dan anotasikan dengan @Test.
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen(){
}
  1. Temukan tombol One Cupcake berdasarkan ID resource string dan lakukan tindakan klik pada tombol tersebut.
import com.example.cupcake.R
...

@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
    composeTestRule.onNodeWithStringId(R.string.one_cupcake)
        .performClick()
}
  1. Nyatakan bahwa nama rute saat ini adalah nama layar Rasa.
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
    composeTestRule.onNodeWithStringId(R.string.one_cupcake)
        .performClick()
    navController.assertCurrentRouteName(CupcakeScreen.Flavor.name)
}

Menulis metode bantuan lainnya

Aplikasi Cupcake memiliki alur navigasi yang sebagian besar linear. Setelah mengklik tombol Cancel, Anda hanya dapat membuka aplikasi melalui satu arah. Oleh karena itu, saat menguji layar yang lebih lanjut pada aplikasi, Anda dapat mengulangi kode untuk membuka area yang ingin diuji. Situasi ini membutuhkan penggunaan lebih banyak metode bantuan sehingga Anda hanya perlu menulis kode tersebut sekali.

Setelah menguji navigasi ke layar Rasa, buat metode yang menavigasi ke layar Rasa sehingga Anda tidak perlu mengulangi kode tersebut untuk pengujian mendatang.

  1. Buat metode yang disebut navigateToFlavorScreen().
private fun navigateToFlavorScreen() {
}
  1. Tulis perintah untuk menemukan tombol One Cupcake dan lakukan tindakan klik pada tombol tersebut, seperti yang Anda lakukan di bagian sebelumnya.
private fun navigateToFlavorScreen() {
    composeTestRule.onNodeWithStringId(R.string.one_cupcake)
        .performClick()
}

Ingat bahwa tombol Next di layar Rasa tidak akan dapat diklik hingga rasa dipilih Metode ini hanya dimaksudkan untuk menyiapkan UI bagi navigasi. Setelah Anda memanggil metode ini, UI harus dalam status yang memungkinkan tombol Next dapat diklik.

  1. Temukan node di UI dengan string R.string.chocolate dan lakukan tindakan klik pada node tersebut untuk memilihnya.
private fun navigateToFlavorScreen() {
    composeTestRule.onNodeWithStringId(R.string.one_cupcake)
        .performClick()
    composeTestRule.onNodeWithStringId(R.string.chocolate)
        .performClick()
}

Lihat apakah Anda dapat menulis metode bantuan yang membuka layar Pengambilan dan layar Ringkasan. Cobalah latihan ini sendiri sebelum melihat solusinya.

Gunakan kode berikut untuk melakukannya:

private fun getFormattedDate(): String {
    val calendar = Calendar.getInstance()
    calendar.add(java.util.Calendar.DATE, 1)
    val formatter = SimpleDateFormat("E MMM d", Locale.getDefault())
    return formatter.format(calendar.time)
}
private fun navigateToPickupScreen() {
    navigateToFlavorScreen()
    composeTestRule.onNodeWithStringId(R.string.next)
        .performClick()
}

private fun navigateToSummaryScreen() {
    navigateToPickupScreen()
    composeTestRule.onNodeWithText(getFormattedDate())
        .performClick()
    composeTestRule.onNodeWithStringId(R.string.next)
        .performClick()
}

Saat menguji layar di luar layar Mulai, Anda harus menguji fungsi tombol Atas untuk memastikan layar mengarahkan navigasi ke layar sebelumnya. Pertimbangkan untuk membuat fungsi bantuan untuk menemukan dan mengklik tombol Atas.

private fun performNavigateUp() {
    val backText = composeTestRule.activity.getString(R.string.back_button)
    composeTestRule.onNodeWithContentDescription(backText).performClick()
}

Memaksimalkan cakupan pengujian

Rangkaian pengujian aplikasi harus menguji fungsi aplikasi sebanyak mungkin. Dalam lingkungan yang sempurna, rangkaian pengujian UI akan mencakup 100% fungsi UI. Dalam praktiknya, jumlah cakupan pengujian ini sulit dicapai karena ada banyak faktor di luar aplikasi yang dapat memengaruhi UI, seperti perangkat dengan ukuran layar unik, versi sistem operasi Android yang berbeda, dan aplikasi pihak ketiga yang dapat memengaruhi aplikasi lain di ponsel.

Salah satu cara untuk memaksimalkan cakupan pengujian adalah dengan menulis pengujian bersama fitur saat Anda menambahkannya. Dengan demikian, Anda tidak akan terlalu jauh membuat fitur baru dan harus kembali untuk mengingat semua kemungkinan skenario. Cupcake adalah aplikasi yang cukup kecil untuk saat ini, dan Anda sudah menguji sebagian besar navigasi aplikasi. Namun, masih banyak status navigasi yang perlu diuji.

Lihat apakah Anda dapat menulis pengujian untuk memverifikasi status navigasi berikut. Coba implementasikan sendiri sebelum melihat solusinya.

  • Membuka layar Mulai dengan mengklik tombol Atas dari layar Rasa
  • Membuka layar Mulai dengan mengklik tombol Cancel dari layar Rasa
  • Membuka layar Pengambilan
  • Membuka layar Rasa dengan mengklik tombol Atas dari layar Pengambilan
  • Membuka layar Mulai dengan mengklik tombol Cancel dari layar Pengambilan
  • Membuka layar Ringkasan
  • Membuka layar Mulai dengan mengklik tombol Cancel dari layar Ringkasan
@Test
fun cupcakeNavHost_clickNextOnFlavorScreen_navigatesToPickupScreen() {
    navigateToFlavorScreen()
    composeTestRule.onNodeWithStringId(R.string.next)
        .performClick()
    navController.assertCurrentRouteName(CupcakeScreen.Pickup.name)
}

@Test
fun cupcakeNavHost_clickBackOnFlavorScreen_navigatesToStartOrderScreen() {
    navigateToFlavorScreen()
    performNavigateUp()
    navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

@Test
fun cupcakeNavHost_clickCancelOnFlavorScreen_navigatesToStartOrderScreen() {
    navigateToFlavorScreen()
    composeTestRule.onNodeWithStringId(R.string.cancel)
        .performClick()
    navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

@Test
fun cupcakeNavHost_clickNextOnPickupScreen_navigatesToSummaryScreen() {
    navigateToPickupScreen()
    composeTestRule.onNodeWithText(getFormattedDate())
        .performClick()
    composeTestRule.onNodeWithStringId(R.string.next)
        .performClick()
    navController.assertCurrentRouteName(CupcakeScreen.Summary.name)
}

@Test
fun cupcakeNavHost_clickBackOnPickupScreen_navigatesToFlavorScreen() {
    navigateToPickupScreen()
    performNavigateUp()
    navController.assertCurrentRouteName(CupcakeScreen.Flavor.name)
}

@Test
fun cupcakeNavHost_clickCancelOnPickupScreen_navigatesToStartOrderScreen() {
    navigateToPickupScreen()
    composeTestRule.onNodeWithStringId(R.string.cancel)
        .performClick()
    navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

@Test
fun cupcakeNavHost_clickCancelOnSummaryScreen_navigatesToStartOrderScreen() {
    navigateToSummaryScreen()
    composeTestRule.onNodeWithStringId(R.string.cancel)
        .performClick()
    navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

6. Menulis pengujian untuk layar Pesanan

Navigasi hanyalah salah satu aspek dari fungsi aplikasi Cupcake. Pengguna juga berinteraksi dengan setiap layar aplikasi. Anda harus memverifikasi apa yang muncul di layar tersebut dan tindakan yang dilakukan di layar tersebut memberikan hasil yang benar. SelectOptionScreen adalah bagian penting dari aplikasi.

Di bagian ini, Anda menulis pengujian untuk memverifikasi bahwa konten di layar ini ditetapkan dengan benar.

Menguji konten layar Pilih Rasa

  1. Buat class baru di dalam direktori app/src/androidTest yang disebut CupcakeOrderScreenTest, tempat file pengujian lainnya berada.

1aaa3be367a02dcd.png

  1. Di class ini, buat AndroidComposeTestRule.
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
  1. Buat fungsi dengan nama selectOptionScreen_verifyContent() dan anotasikan dengan @Test.
@Test
fun selectOptionScreen_verifyContent() {

}

Dalam fungsi ini, pada akhirnya Anda menetapkan konten aturan Compose ke SelectOptionScreen. Tindakan ini memastikan bahwa composable SelectOptionScreen diluncurkan secara langsung sehingga navigasi tidak diperlukan. Namun, layar ini memerlukan dua parameter: daftar opsi rasa dan subtotal.

  1. Buat daftar opsi rasa dan subtotal untuk diteruskan ke layar.
@Test
fun selectOptionScreen_verifyContent() {
    // Given list of options
    val flavors = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
    // And subtotal
    val subtotal = "$100"
}
  1. Setel konten ke composable SelectOptionScreen menggunakan nilai yang baru saja Anda buat.

Perhatikan bahwa pendekatan ini mirip dengan meluncurkan composable dari MainActivity. Satu-satunya perbedaan adalah MainActivity memanggil composable CupcakeApp, dan di sini Anda memanggil composable SelectOptionScreen. Kemampuan untuk mengubah composable yang diluncurkan dari setContent() memungkinkan Anda meluncurkan composable tertentu, bukan meminta pengujian secara eksplisit untuk menelusuri aplikasi agar dapat sampai ke area yang ingin diuji. Pendekatan ini membantu mencegah pengujian gagal di area kode yang tidak terkait dengan pengujian Anda saat ini.

@Test
fun selectOptionScreen_verifyContent() {
    // Given list of options
    val flavors = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
    // And subtotal
    val subtotal = "$100"

    // When SelectOptionScreen is loaded
    composeTestRule.setContent {
        SelectOptionScreen(subtotal = subtotal, options = flavors)
    }
}

Pada tahap pengujian ini, aplikasi akan meluncurkan composable SelectOptionScreen dan kemudian Anda dapat berinteraksi dengannya melalui petunjuk pengujian.

  1. Lakukan iterasi melalui daftar flavors dan pastikan setiap item string dalam daftar ditampilkan di layar.
  2. Gunakan metode onNodeWithText() untuk menemukan teks di layar dan gunakan metode assertIsDisplayed() untuk memverifikasi bahwa teks ditampilkan di aplikasi.
@Test
fun selectOptionScreen_verifyContent() {
    // Given list of options
    val flavors = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
    // And subtotal
    val subtotal = "$100"

    // When SelectOptionScreen is loaded
    composeTestRule.setContent {
        SelectOptionScreen(subtotal = subtotal, options = flavors)
    }

    // Then all the options are displayed on the screen.
    flavors.forEach { flavor ->
        composeTestRule.onNodeWithText(flavor).assertIsDisplayed()
    }
}
  1. Dengan menggunakan teknik yang sama untuk memverifikasi bahwa aplikasi menampilkan teks, verifikasi bahwa aplikasi menampilkan string subtotal yang benar di layar. Telusuri ID resource R.string.subtotal_price dan nilai subtotal yang benar di layar, lalu nyatakan bahwa aplikasi menampilkan nilai.
import com.example.cupcake.R
...

@Test
fun selectOptionScreen_verifyContent() {
    // Given list of options
    val flavors = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
    // And subtotal
    val subtotal = "$100"

    // When SelectOptionScreen is loaded
    composeTestRule.setContent {
        SelectOptionScreen(subtotal = subtotal, options = flavors)
    }

    // Then all the options are displayed on the screen.
    flavors.forEach { flavor ->
        composeTestRule.onNodeWithText(flavor).assertIsDisplayed()
    }

    // And then the subtotal is displayed correctly.
    composeTestRule.onNodeWithText(
        composeTestRule.activity.getString(
            R.string.subtotal_price,
            subtotal
        )
    ).assertIsDisplayed()
}

Ingat bahwa tombol Next tidak diaktifkan hingga item dipilih. Pengujian ini hanya memverifikasi konten layar, sehingga hal terakhir yang perlu diuji adalah tombol Next dinonaktifkan.

  1. Temukan tombol Next dengan menggunakan pendekatan yang sama untuk menemukan node berdasarkan ID resource string. Namun, gunakan metode assertIsNotEnabled(), bukan memverifikasi bahwa aplikasi menampilkan node.
@Test
fun selectOptionScreen_verifyContent() {
    // Given list of options
    val flavors = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
    // And subtotal
    val subtotal = "$100"

    // When SelectOptionScreen is loaded
    composeTestRule.setContent {
        SelectOptionScreen(subtotal = subtotal, options = flavors)
    }

    // Then all the options are displayed on the screen.
    flavors.forEach { flavor ->
        composeTestRule.onNodeWithText(flavor).assertIsDisplayed()
    }

    // And then the subtotal is displayed correctly.
    composeTestRule.onNodeWithText(
        composeTestRule.activity.getString(
            R.string.subtotal_price,
            subtotal
        )
    ).assertIsDisplayed()

    // And then the next button is disabled
    composeTestRule.onNodeWithStringId(R.string.next).assertIsNotEnabled()
}

Memaksimalkan cakupan pengujian

Pengujian konten layar Choose Flavor hanya menguji satu aspek dari satu layar. Ada sejumlah pengujian tambahan yang dapat Anda tulis untuk meningkatkan cakupan kode. Coba tulis pengujian berikut sendiri sebelum mendownload kode solusi.

  • Verifikasi konten layar Mulai.
  • Verifikasi konten layar Ringkasan.
  • Pastikan tombol Next diaktifkan saat opsi dipilih di layar Pilih Rasa.

Saat menulis pengujian, perhatikan setiap fungsi bantuan yang dapat mengurangi jumlah kode yang Anda tulis.

7. Mendapatkan kode solusi

Guna mendownload kode untuk codelab yang sudah selesai, Anda dapat menggunakan perintah git ini:

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-cupcake.git

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

Jika Anda ingin melihat kode solusi, lihat di GitHub.

8. Ringkasan

Selamat! Anda telah mempelajari cara menguji komponen Jetpack Navigation. Anda juga telah mempelajari beberapa keterampilan dasar untuk menulis pengujian UI, seperti menulis metode bantuan yang dapat digunakan kembali, cara memanfaatkan setContent() untuk menulis pengujian yang ringkas, cara menyiapkan pengujian dengan anotasi @Before, dan cara mempertimbangkan nilai maksimum cakupan pengujian. Saat melanjutkan membangun aplikasi Android, jangan lupa untuk terus menulis pengujian bersama kode fitur Anda.