1. 簡介
在「使用 Compose 切換螢幕」程式碼研究室中,您已瞭解如何使用 Jetpack Navigation Compose 元件在 Compose 應用程式中新增導覽功能。
Cupcake 應用程式有多個畫面可前往,且使用者可以執行多項操作。這個應用程式為您提供了提升自動測試技能的絕佳機會!在本程式碼研究室中,您將為 Cupcake 應用程式編寫一些 UI 測試,並瞭解如何盡量擴大測試涵蓋範圍。
必要條件
- 熟悉 Kotlin 語言,包括函式類型、lambda 和範圍函式
- 完成「使用 Compose 切換螢幕」程式碼研究室
課程內容
- 使用 Compose 測試 Jetpack Navigation 元件。
- 為每個 UI 測試建立一致的 UI 狀態。
- 為測試建立輔助函式。
建構項目
- Cupcake 應用程式的 UI 測試
軟硬體需求
- 最新版 Android Studio
- 需連線至網路來下載範例程式碼
2. 下載範例程式碼
- 在 Android Studio 中開啟
basic-android-kotlin-compose-training-cupcake
資料夾。 - 在 Android Studio 中開啟 Cupcake 應用程式程式碼。
3. 設定 Cupcake 以進行 UI 測試
新增 androidTest
依附元件
您可以使用 Gradle 建構工具為特定模組新增依附元件。這項功能可避免對依附元件進行不必要的編譯。在專案中加入依附元件時,您已熟悉 implementation
設定。您已使用此關鍵字在應用程式模組的 build.gradle.kts
檔案中匯入依附元件。使用 implementation
關鍵字,即可將依附元件提供給該模組中的所有來源集使用。在本課程的這一階段,您已經具備處理 main
、test
和 androidTest
來源集的經驗。
UI 測試包含在名為 androidTest
的獨立來源集中。如果依附元件只需要應用於該模組,就不必針對其他模組 (例如包含應用程式程式碼的 main
模組) 進行編譯。新增僅用於 UI 測試的依附元件時,請使用 androidTestImplementation
關鍵字,在應用程式模組的 build.gradle.kts
檔案中宣告依附元件。這麼做可確保只有在您執行 UI 測試時,系統才會編譯 UI 測試依附元件。
請完成下列步驟,新增編寫 UI 測試所需的依附元件:
- 開啟
build.gradle.kts(Module :app)
檔案。 - 在檔案的
dependencies
部分新增下列依附元件:
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")
建立 UI 測試目錄
- 在專案檢視畫面中的
src
目錄上按一下滑鼠右鍵,然後依序選取「New」>「Directory」。
- 選取「androidTest/java」選項。
建立測試套件
- 在專案視窗中的
androidTest/java
目錄上按一下滑鼠右鍵,然後依序選取「New」>「Package」。
- 將套件命名為 com.example.cupcake.test。
建立導覽測試類別
在 test
目錄中,建立名為 CupcakeScreenNavigationTest
的新 Kotlin 類別。
4. 設定導覽主機
在先前的程式碼研究室中,您已瞭解 Compose 中的 UI 測試需具備 Compose 測試規則。測試 Jetpack Navigation 也是如此。不過,測試導覽時必須透過 Compose 測試規則進行一些額外設定。
測試 Compose Navigation 時,您無法在應用程式程式碼中存取相同的 NavHostController
。不過,您可以使用 TestNavHostController
並設定這個導覽控制器的測試規則。本節將說明如何針對導覽測試設定測試規則並重複使用。
- 在
CupcakeScreenNavigationTest.kt
中使用createAndroidComposeRule
建立測試規則,並將ComponentActivity
做為類型參數傳遞。
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import org.junit.Rule
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
為確保應用程式導覽至正確的位置,您需要在應用程式執行導覽操作時,參照 TestNavHostController
例項來檢查導覽主機的導覽路徑。
- 對
TestNavHostController
例項進行例項化,使其成為lateinit
變數。在 Kotlin 中,lateinit
關鍵字可用來宣告在宣告物件之後可初始化的屬性。
import androidx.navigation.testing.TestNavHostController
private lateinit var navController: TestNavHostController
接著,指定要用於 UI 測試的可組合函式。
- 建立名為
setupCupcakeNavHost()
的方法。 - 在
setupCupcakeNavHost()
方法中,針對您建立的 Compose 測試規則呼叫setContent()
方法。 - 在傳遞至
setContent()
方法的 lambda 中,呼叫CupcakeApp()
可組合函式。
import com.example.cupcake.CupcakeApp
fun setupCupcakeNavHost() {
composeTestRule.setContent {
CupcakeApp()
}
}
現在,您必須在測試類別中建立 TestNavHostContoller
物件。您稍後會使用這個物件判斷導覽狀態,因為應用程式會使用控制器在 Cupcake 應用程式中的各畫面間導覽。
- 使用您先前建立的 lambda 設定導覽主機。初始化您建立的
navController
變數、註冊導覽器,然後將該TestNavHostController
傳遞至CupcakeApp
可組合函式。
import androidx.compose.ui.platform.LocalContext
fun setupCupcakeNavHost() {
composeTestRule.setContent {
navController = TestNavHostController(LocalContext.current).apply {
navigatorProvider.addNavigator(ComposeNavigator())
}
CupcakeApp(navController = navController)
}
}
CupcakeScreenNavigationTest
類別中的每個測試都包含導覽方面的測試。因此,每項測試都取決於您建立的 TestNavHostController
物件。您可以使用 junit 程式庫提供的 @Before
註解來自動設定導覽控制器,不必為每個測試手動呼叫 setupCupcakeNavHost()
函式。如果某個方法含有 @Before
註解,它會在每個含有 @Test
註解的方法之前執行。
- 將
@Before
註解新增至setupCupcakeNavHost()
方法。
import org.junit.Before
@Before
fun setupCupcakeNavHost() {
composeTestRule.setContent {
navController = TestNavHostController(LocalContext.current).apply {
navigatorProvider.addNavigator(ComposeNavigator())
}
CupcakeApp(navController = navController)
}
}
5. 編寫導覽測試
驗證起始目標頁面
提醒您,建構 Cupcake 應用程式時,您會建立名為 CupcakeScreen
的 enum
類別,其中包含用來控管應用程式導覽的常數。
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)
}
所有具備 UI 的應用程式都有某種類型的主畫面。Cupcake 的主畫面是「Start Order Screen」。CupcakeApp
可組合函式中的導覽控制器會使用 CupcakeScreen
列舉的 Start
項目決定前往該畫面的時機。應用程式啟動後,如果目的地路徑尚未存在,系統會將導覽主機的目的地路徑設為 CupcakeScreen.Start.name
。
您必須先編寫測試,用來驗證應用程式啟動時,「Start Order Screen」是否為當下的目的地路徑。
- 建立名為
cupcakeNavHost_verifyStartDestination()
的函式,並以@Test
加上註解。
import org.junit.Test
@Test
fun cupcakeNavHost_verifyStartDestination() {
}
現在,您必須確認導覽控制器的初始目的地路徑為「Start Order Screen」。
- 斷言的預期路徑名稱 (本例中為
CupcakeScreen.Start.name
) 等於導覽控制器目前返回堆疊項目的目的地路徑。
import org.junit.Assert.assertEquals
...
@Test
fun cupcakeNavHost_verifyStartDestination() {
assertEquals(CupcakeScreen.Start.name, navController.currentBackStackEntry?.destination?.route)
}
建立輔助方法
UI 測試通常需要重複步驟,才能將 UI 設為可測試特定 UI 部分的狀態。自訂 UI 可能也會需要進行複雜斷言,此類斷言需要多行程式碼。您在上一節編寫的斷言需要大量程式碼,而您在 Cupcake 應用程式中測試導覽時會多次使用相同的斷言。在這種情況下,只要在測試中編寫輔助方法,即可不必編寫重複的程式碼。
針對每個您編寫的導覽測試,您可以使用 CupcakeScreen
列舉項目的 name
屬性,檢查導覽控制器目前的目的地路徑是否正確。您可以編寫輔助函式,以便在要進行此類斷言時隨時呼叫。
如要建立輔助函式,請完成下列步驟:
- 在
test
目錄中建立名為ScreenAssertions
的空白 Kotlin 檔案。
- 將擴充功能函式新增至名為
assertCurrentRouteName()
的NavController
類別,並將預期路徑名稱的字串傳入方法簽章中。
fun NavController.assertCurrentRouteName(expectedRouteName: String) {
}
- 在這個函式中,斷言
expectedRouteName
等於導覽控制器目前的返回堆疊項目的目的地路徑。
import org.junit.Assert.assertEquals
...
fun NavController.assertCurrentRouteName(expectedRouteName: String) {
assertEquals(expectedRouteName, currentBackStackEntry?.destination?.route)
}
- 開啟 CupcakeScreenNavigationTest 檔案,並修改
cupcakeNavHost_verifyStartDestination()
函式,以便使用新的擴充功能函式,而非冗長的斷言。
@Test
fun cupcakeNavHost_verifyStartDestination() {
navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}
許多測試也必須與 UI 元件互動。在本程式碼研究室中,通常可以使用資源字串找到這些元件。您可以使用 Context.getString()
方法,依據資源字串存取相關可組合函式,詳情請參閱這裡的相關說明。在 Compose 中編寫 UI 測試時,此方法的實作方式如下所示:
composeTestRule.onNodeWithText(composeTestRule.activity.getString(R.string.my_string)
這是詳細的指示,且只要加入擴充功能函式即可予以簡化。
- 在
com.example.cupcake.test
套件中建立名為 ComposeRuleExtensions.kt 的新檔案。請確認這是純文字的 Kotlin 檔案。
- 將以下程式碼加到該檔案中。
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))
這個擴充功能函式可讓您在依字串資源尋找 UI 元件時,減少編寫的程式碼數量,而不是以下列方式編寫:
composeTestRule.onNodeWithText(composeTestRule.activity.getString(R.string.my_string)
現在可以使用下列指示:
composeTestRule.onNodeWithStringId(R.string.my_string)
確認「Start」畫面沒有「向上」按鈕
Cupcake 應用程式的原始設計中,「Start」畫面的工具列並不包含「向上」按鈕。
「Start」畫面缺少向上按鈕,原因是這個畫面是初始畫面,無法向上導覽。請按照下列步驟建立用於確認「開始」畫面沒有「向上」按鈕的函式:
- 建立名為
cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen()
的方法,並加上@Test
註解。
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
}
在 Cupcake 中,「向上」按鈕的內容說明會設為 R.string.back_button
資源的字串。
- 在測試函式中使用
R.string.back_button
資源的值建立變數。
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
val backText = composeTestRule.activity.getString(R.string.back_button)
}
- 斷言螢幕畫面上沒有包含此內容說明的節點。
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
val backText = composeTestRule.activity.getString(R.string.back_button)
composeTestRule.onNodeWithContentDescription(backText).assertDoesNotExist()
}
驗證前往「Flavor」畫面的導覽
點選「Start」畫面上的任一按鈕,都能觸發會指示導覽控制器前往「Flavor」畫面的方法。
在本測試中,您將編寫指令,用於在使用者點選按鈕時,觸發導覽並驗證目的地路徑為「Flavor」畫面。
- 建立名為
cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen()
的函式,並加上@Test
註解。
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen(){
}
- 依據字串資源 ID 找出「One Cupcake」按鈕,然後對其執行點擊動作。
import com.example.cupcake.R
...
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
composeTestRule.onNodeWithStringId(R.string.one_cupcake)
.performClick()
}
- 斷言目前的路徑名稱為「Flavor」畫面名稱。
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
composeTestRule.onNodeWithStringId(R.string.one_cupcake)
.performClick()
navController.assertCurrentRouteName(CupcakeScreen.Flavor.name)
}
編寫更多輔助方法
Cupcake 應用程式主要採用線性導覽流程。如果不點選「Cancel」按鈕,則只能向單一方向瀏覽應用程式。因此,當您要測試應用程式中更深層的畫面時,會發現自己要重複編寫程式碼才能前往要測試的區域。在這種情況下,有必要使用更多輔助方法,讓您只需要編寫一次程式碼。
現在,您已測試了前往「Flavor」畫面的導覽,接著請建立前往「Flavor」畫面的方法,這樣您就不需要在後續測試中重複編寫該程式碼。
- 建立名為
navigateToFlavorScreen()
的方法。
private fun navigateToFlavorScreen() {
}
- 依照上一節介紹的做法,編寫指令來找出「One Cupcake」按鈕,並對其執行點擊操作。
private fun navigateToFlavorScreen() {
composeTestRule.onNodeWithStringId(R.string.one_cupcake)
.performClick()
}
提醒您,在選取口味之前,「Flavor」畫面的「Next」按鈕無法點選。這個方法只能用來讓 UI 做好導覽準備。呼叫此方法後,UI 應處於「Next」按鈕可點選的狀態。
- 在 UI 中找到含有
R.string.chocolate
字串的節點,然後對其執行點擊動作來選取節點。
private fun navigateToFlavorScreen() {
composeTestRule.onNodeWithStringId(R.string.one_cupcake)
.performClick()
composeTestRule.onNodeWithStringId(R.string.chocolate)
.performClick()
}
請確認您是否能編寫輔助方法,用來前往「Pickup」畫面和「Summary」畫面。請自行練習後再查看解決方案。
請使用以下程式碼完成這項操作:
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()
}
測試「Start」畫面以外的畫面時,必須規劃「向上」按鈕功能測試,確保它能引導使用者前往上一個畫面。請考慮建立輔助函式來找出並點選「向上」按鈕。
private fun performNavigateUp() {
val backText = composeTestRule.activity.getString(R.string.back_button)
composeTestRule.onNodeWithContentDescription(backText).performClick()
}
盡量擴大測試涵蓋範圍
應用程式的測試套件應盡可能測試更多的應用程式功能。最完美的情況,是 UI 測試套件的範圍能涵蓋 100% 的 UI 功能。實際上,由於應用程式有許多會影響 UI 的外部因素,因此測試很難達到完美的涵蓋範圍。例如裝置有特殊的螢幕尺寸、Android 作業系統版本不同,以及會影響手機上其他應用程式的第三方應用程式等。
如要盡可能擴大測試涵蓋範圍,其中一種方法是在新增功能時一併編寫測試。如此一來,您就不必在新功能已有深入開發進展時,還必須重新回想所有可能的情境。目前,Cupcake 是相當小的應用程式,您已測試該應用程式導覽的一大部分!不過,還有其他導覽狀態需要測試。
請確認您是否能編寫測試來驗證下列導覽狀態。建議您先自行實作,再查看解決方案。
- 按一下「Flavor」畫面中的「向上」按鈕,前往「Start」畫面
- 按一下「Flavor」畫面中的「Cancel」按鈕,前往「Start」畫面
- 前往「Pickup」畫面
- 按一下「Pickup」畫面中的「向上」按鈕,前往「Flavor」畫面
- 按一下「Pickup」畫面中的「Cancel」按鈕,前往「Start」畫面
- 前往「Summary」畫面
- 按一下「Summary」畫面中的「Cancel」按鈕,前往「Start」畫面。
@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. 編寫「Order」畫面的測試
導覽只是 Cupcake 應用程式功能的一部分。使用者也會與每個應用程式畫面互動。您需要驗證這些畫面上顯示的內容,以及在這些畫面上執行的動作是否會產生正確結果。SelectOptionScreen 是應用程式的重要部分。
在本節中,您將編寫測試,驗證此畫面中的內容是否已正確設定。
測試「Choose Flavor」畫面內容
- 在
app/src/androidTest
目錄中建立名為CupcakeOrderScreenTest
的新類別,這個目錄包含其他測試檔案。
- 在這個類別中,建立
AndroidComposeTestRule
。
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
- 建立名為
selectOptionScreen_verifyContent()
的函式,並以@Test
加上註解。
@Test
fun selectOptionScreen_verifyContent() {
}
在此函式中,您最後會將 Compose 規則內容設為 SelectOptionScreen
。這麼做可確保 SelectOptionScreen
可組合函式會直接啟動,因此不需要導覽。不過,這個畫面需要兩個參數:口味選項清單和小計。
- 建立要傳遞給畫面的口味選項清單和小計。
@Test
fun selectOptionScreen_verifyContent() {
// Given list of options
val flavors = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
// And subtotal
val subtotal = "$100"
}
- 使用剛才建立的值,將內容設為
SelectOptionScreen
可組合函式。
請注意,這個方法與從 MainActivity
啟動可組合函式類似。唯一的差別在於,MainActivity
會呼叫 CupcakeApp
可組合函式,而此處會呼叫 SelectOptionScreen
可組合函式。透過變更從 setContent()
啟動的可組合函式,您可以啟動特定可組合函式,不必在測試中循序漸進地執行應用程式來前往要測試的區域。這種做法有助於避免在與目前測試無關的程式碼中失敗。
@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)
}
}
在測試的當前階段,應用程式會啟動 SelectOptionScreen
可組合函式,然後您就可以透過測試操作說明與其互動。
- 透過
flavors
清單進行疊代,確保清單中的每個字串項目都顯示在畫面上。 - 使用
onNodeWithText()
方法尋找畫面上的文字,並使用assertIsDisplayed()
方法驗證文字是否已顯示在應用程式中。
@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()
}
}
- 使用相同技巧驗證應用程式是否會顯示文字,確認應用程式已在螢幕上顯示正確的小計字串。在畫面上搜尋
R.string.subtotal_price
資源 ID 和正確的小計值,然後斷言應用程式會顯示該值。
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()
}
提醒您,您必須先選取項目,才能啟用「Next」按鈕。這項測試只會驗證畫面內容,因此最後要測試的部分是「Next」按鈕是否已停用。
- 使用相同方法,透過字串資源 ID 尋找節點,來找出「Next」按鈕。不過,請使用
assertIsNotEnabled()
方法,而不要驗證應用程式是否顯示節點。
@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()
}
盡量擴大測試涵蓋範圍
「Choose Flavor」畫面內容測試只能測試單一畫面的一個部分。您可以編寫一些額外測試來擴大程式碼涵蓋範圍。下載解決方案程式碼前,請先嘗試自行編寫下列測試。
- 驗證「Start」畫面內容。
- 驗證「Summary」畫面內容。
- 驗證在「Choose Flavor」畫面中選取選項時,「Next」按鈕為啟用狀態。
編寫測試時,請留意任何有助於減少程式碼編寫量的輔助函式。
7. 取得解決方案程式碼
完成程式碼研究室後,如要下載當中用到的程式碼,您可以使用以下 Git 指令:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-cupcake.git
另外,您也可以下載存放區為 ZIP 檔案,然後解壓縮並在 Android Studio 中開啟。
如要查看解決方案程式碼,請前往 GitHub。
8. 摘要
恭喜!您已瞭解如何測試 Jetpack Navigation 元件,也學到了編寫 UI 測試的一些基本技能,例如編寫可重複使用的輔助方法、如何利用 setContent()
編寫簡潔測試、透過 @Before
註解設定測試,以及如何盡可能擴展測試涵蓋率。往後建構 Android 應用程式時,除了編寫應用程式功能外,也別忘了編寫測試!