测试 Cupcake 应用

1. 简介

使用 Compose 在屏幕之间导航 Codelab 中,您学习了如何使用 Jetpack Navigation Compose 组件为 Compose 应用添加导航。

Cupcake 应用包含多个屏幕,用户可以在这些屏幕之间导航并执行各种操作。此应用为您提供了磨练自动化测试技能的绝佳机会!在本 Codelab 中,您将为 Cupcake 应用编写多个 UI 测试,并学习如何最大限度地提高测试覆盖率。

前提条件

您将学到什么

  • 使用 Compose 测试 Jetpack Navigation 组件。
  • 为每个 UI 测试创建一个一致的 UI 状态。
  • 为测试创建辅助函数。

您将构建什么

  • Cupcake 应用的 UI 测试

您需要什么

  • 最新版本的 Android Studio
  • 用于下载起始代码的互联网连接

2. 下载起始代码

  1. 在 Android Studio 中,打开 basic-android-kotlin-compose-training-cupcake 文件夹。
  2. 在 Android Studio 中打开 Cupcake 应用代码。

3. 设置 Cupcake 以进行 UI 测试

添加 androidTest 依赖项

Gradle 构建工具允许您为特定模块添加依赖项。此功能可防止不必要的依赖项编译。在项目中包含依赖项时,您已经熟悉 implementation 配置。您已使用此关键字在应用模块的 build.gradle.kts 文件中导入依赖项。使用 implementation 关键字可使该依赖项对该模块中的所有源集可用;在本课程的这一点,您已获得了使用 maintestandroidTest 源集的经验。

UI 测试包含在称为 androidTest 的自己的源集中。仅此模块所需的依赖项无需为其他模块(例如包含应用代码的 main 模块)进行编译。当添加仅供 UI 测试使用的依赖项时,请使用 androidTestImplementation 关键字在应用模块的 build.gradle.kts 文件中声明该依赖项。这样做可以确保仅在运行 UI 测试时才编译 UI 测试依赖项。

完成以下步骤以添加编写 UI 测试所需的依赖项

  1. 打开 build.gradle.kts(Module :app) 文件。
  2. 将以下依赖项添加到文件的 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 测试目录

  1. 右键点击项目视图中的 src 目录,然后选择 New > Directory

290b1ab99ce8f4e5.png

  1. 选择 androidTest/java 选项。

718bde5eb21b4f6f.png

创建测试包

  1. 右键点击项目窗口中的 androidTest/java 目录,然后选择 New > Package

7ad315f41e2b0881.png

  1. 将软件包命名为 com.example.cupcake.testb8306f9d11988a2.png

创建导航测试类

test 目录中,创建一个新的 Kotlin 类,名为 CupcakeScreenNavigationTest

5515db35968f7d86.png

4b527e7404fad927.png

4. 设置导航宿主

在之前的 Codelab 中,您学习了 Compose 中的 UI 测试需要一个 Compose 测试规则。测试 Jetpack Navigation 也是如此。但是,测试导航需要通过 Compose 测试规则进行一些额外的设置。

测试 Compose Navigation 时,您将无法访问应用代码中的相同 NavHostController。但是,您可以使用 TestNavHostController 并使用此导航控制器配置测试规则。在本部分中,您将学习如何配置和重用导航测试的测试规则。

  1. 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 实例,以便在应用执行导航操作时检查导航宿主的导航路线。

  1. TestNavHostContoller 实例实例化为一个 lateinit 变量。在 Kotlin 中,lateinit 关键字用于声明一个可以在对象声明后初始化的属性。
import androidx.navigation.testing.TestNavHostController

private lateinit var navController: TestNavHostController

接下来,指定要用于 UI 测试的可组合项。

  1. 创建一个名为 setupCupcakeNavHost() 的方法。
  2. setupCupcakeNavHost() 方法中,在您创建的 Compose 测试规则上调用 setContent() 方法。
  3. 在传递给 setContent() 方法的 lambda 内部,调用 CupcakeApp() 可组合项。
import com.example.cupcake.CupcakeApp

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

现在,您需要在测试类中创建 TestNavHostContoller 对象。您稍后将使用此对象来确定导航状态,因为应用使用该控制器在 Cupcake 应用的各个屏幕之间导航。

  1. 使用您之前创建的 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 对象。您无需为每个测试手动调用 setupCupcakeNavHost() 函数来设置导航控制器,而是可以使用 junit 库提供的 @Before 注解自动实现。当一个方法带有 @Before 注解时,它将在每个带有 @Test 注解的方法之前运行。

  1. @Before 注解添加到 setupCupcakeNavHost() 方法。
import org.junit.Before

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

5. 编写导航测试

验证起始目的地

回想一下,在您构建 Cupcake 应用时,您创建了一个名为 CupcakeScreenenum 类,其中包含用于指示应用导航的常量。

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,该屏幕是开始订购屏幕CupcakeApp 可组合项中的导航控制器使用 CupcakeScreen 枚举的 Start 项来确定何时导航到此屏幕。当应用启动时,如果目的地路线尚不存在,则导航宿主目的地路线将设置为 CupcakeScreen.Start.name

您首先需要编写一个测试来验证 开始订购屏幕 是否是应用启动时的当前目的地路线。

  1. 创建一个名为 cupcakeNavHost_verifyStartDestination() 的函数,并使用 @Test 对其进行注解。
import org.junit.Test

@Test
fun cupcakeNavHost_verifyStartDestination() {
}

现在,您必须确认导航控制器的初始目的地路线是开始订购屏幕

  1. 断言预期的路线名称(在本例中为 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 属性来检查导航控制器的当前目的地路线是否正确。您可以编写一个辅助函数,以便在需要进行此类断言时调用它。

完成以下步骤以创建此辅助函数

  1. test 目录中创建一个空的 Kotlin 文件,名为 ScreenAssertions

63af08bd78a827c4.png

  1. NavController 类添加一个名为 assertCurrentRouteName() 的扩展函数,并在方法签名中传递一个字符串作为预期的路线名称。
fun NavController.assertCurrentRouteName(expectedRouteName: String) {

}
  1. 在此函数中,断言 expectedRouteName 等于导航控制器的当前返回堆栈条目的目的地路线。
import org.junit.Assert.assertEquals
...

fun NavController.assertCurrentRouteName(expectedRouteName: String) {
    assertEquals(expectedRouteName, currentBackStackEntry?.destination?.route)
}
  1. 打开 CupcakeScreenNavigationTest 文件,修改 cupcakeNavHost_verifyStartDestination() 函数,使其使用您新的扩展函数而不是冗长的断言。
@Test
fun cupcakeNavHost_verifyStartDestination() {
    navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

许多测试还需要与 UI 组件进行交互。在本 Codelab 中,通常使用资源字符串查找这些组件。您可以使用 Context.getString() 方法通过其资源字符串访问可组合项,您可以在此处了解相关信息。在 Compose 中编写 UI 测试时,实现此方法如下所示:

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

这是一个冗长的指令,可以通过添加扩展函数来简化。

  1. com.example.cupcake.test 包中创建一个新文件,名为 ComposeRuleExtensions.kt。请确保这是一个纯 Kotlin 文件。

5710fc2d8219048b.png

  1. 将以下代码添加到该文件。
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)

验证开始屏幕没有向上按钮

Cupcake 应用的原始设计在开始屏幕的工具栏中没有向上按钮。

ffb8d156220c7e57.png

开始屏幕缺少一个按钮,因为无法从此屏幕向上导航,因为它是一个初始屏幕。请按照以下步骤创建一个函数来确认开始屏幕没有向上按钮:

  1. 创建一个名为 cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() 的方法,并使用 @Test 对其进行注解。
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
}

在 Cupcake 中,向上按钮的内容说明设置为来自 R.string.back_button 资源的字符串。

  1. 在测试函数中创建一个变量,其值为 R.string.back_button 资源。
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
    val backText = composeTestRule.activity.getString(R.string.back_button)
}
  1. 断言屏幕上不存在带有此内容说明的节点。
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
    val backText = composeTestRule.activity.getString(R.string.back_button)
    composeTestRule.onNodeWithContentDescription(backText).assertDoesNotExist()
}

验证导航到风味选择屏幕

点击开始屏幕中的一个按钮会触发一个方法,该方法指示导航控制器导航到风味选择屏幕。

3bda045bfe202c90.png

在此测试中,您编写一个命令来点击按钮以触发此导航,并验证目的地路线是风味选择屏幕。

  1. 创建一个名为 cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() 的函数,并使用 @Test 对其进行注解。
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen(){
}
  1. 通过其字符串资源 id 查找一份 Cupcake 按钮,并在其上执行点击操作。
import com.example.cupcake.R
...

@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
    composeTestRule.onNodeWithStringId(R.string.one_cupcake)
        .performClick()
}
  1. 断言当前路线名称是风味选择屏幕名称。
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
    composeTestRule.onNodeWithStringId(R.string.one_cupcake)
        .performClick()
    navController.assertCurrentRouteName(CupcakeScreen.Flavor.name)
}

编写更多辅助方法

Cupcake 应用的导航流程大多是线性的。除了点击取消按钮,您只能在一个方向上导航应用。因此,当您测试应用中更深层的屏幕时,您可能会发现自己重复编写代码以导航到您想要测试的区域。这种情况值得使用更多辅助方法,以便您只需编写一次该代码。

既然您已经测试了导航到风味选择屏幕,请创建一个导航到风味选择屏幕的方法,这样您就不必在未来的测试中重复编写该代码。

  1. 创建一个名为 navigateToFlavorScreen() 的方法。
private fun navigateToFlavorScreen() {
}
  1. 编写一个命令,通过其字符串资源 id 查找一份 Cupcake 按钮,并在其上执行点击操作,就像您在上一节中所做的那样。
private fun navigateToFlavorScreen() {
    composeTestRule.onNodeWithStringId(R.string.one_cupcake)
        .performClick()
}

回想一下,风味选择屏幕上的下一步按钮在选择风味之前是不可点击的。此方法仅用于准备 UI 进行导航。调用此方法后,UI 应处于下一步按钮可点击的状态。

  1. 在 UI 中查找带有 R.string.chocolate 字符串的节点,并在其上执行点击操作以将其选中。
private fun navigateToFlavorScreen() {
    composeTestRule.onNodeWithStringId(R.string.one_cupcake)
        .performClick()
    composeTestRule.onNodeWithStringId(R.string.chocolate)
        .performClick()
}

看看您是否可以编写导航到取货屏幕和汇总屏幕的辅助方法。在查看解决方案之前,请自己尝试一下此练习。

使用以下代码完成此操作:

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

在测试开始屏幕以外的屏幕时,您需要计划测试向上按钮的功能,以确保它将导航定向到上一个屏幕。考虑创建一个辅助函数来查找并点击向上按钮。

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

最大化测试覆盖率

应用的测试套件应尽可能多地测试应用的功能。在理想情况下,UI 测试套件会覆盖 100% 的 UI 功能。实际上,要达到这种测试覆盖率很困难,因为有许多应用外部因素可能会影响 UI,例如具有独特屏幕尺寸的设备、不同版本的 Android 操作系统以及可能会影响手机上其他应用的第三方应用。

帮助最大化测试覆盖率的一种方法是在添加功能时同时编写测试。这样做可以避免在新功能上走得太远,然后不得不回头记住所有可能的场景。Cupcake 目前是一个相当小的应用,您已经测试了应用导航的很大一部分!但是,还有更多导航状态需要测试。

看看您是否可以编写测试来验证以下导航状态。在查看解决方案之前,请尝试自行实现它们。

  • 从风味选择屏幕点击向上按钮导航到开始屏幕
  • 从风味选择屏幕点击取消按钮导航到开始屏幕
  • 导航到取货屏幕
  • 从取货屏幕点击向上按钮导航到风味选择屏幕
  • 从取货屏幕点击取消按钮导航到开始屏幕
  • 导航到汇总屏幕
  • 从汇总屏幕点击取消按钮导航到开始屏幕
@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. 编写订购屏幕的测试

导航只是 Cupcake 应用功能的其中一个方面。用户还会与应用的每个屏幕进行交互。您需要验证这些屏幕上显示的内容以及在这些屏幕上执行的操作是否产生正确的结果。SelectOptionScreen 是应用的重要组成部分。

在本节中,您将编写一个测试来验证此屏幕上的内容是否已正确设置。

测试选择风味屏幕内容

  1. app/src/androidTest 目录中创建一个新类,名为 CupcakeOrderScreenTest,您的其他测试文件也包含在此处。

1aaa3be367a02dcd.png

  1. 在此类中,创建一个 AndroidComposeTestRule
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
  1. 创建一个名为 selectOptionScreen_verifyContent() 的函数,并使用 @Test 对其进行注解。
@Test
fun selectOptionScreen_verifyContent() {

}

在此函数中,您最终会将 Compose 规则内容设置为 SelectOptionScreen。这样做可以确保直接启动 SelectOptionScreen 可组合项,从而无需导航。但是,此屏幕需要两个参数:风味选项列表和小计。

  1. 创建一个风味选项列表和小计,以传递给屏幕。
@Test
fun selectOptionScreen_verifyContent() {
    // Given list of options
    val flavors = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
    // And subtotal
    val subtotal = "$100"
}
  1. 使用您刚刚创建的值将内容设置为 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 可组合项,然后您就可以通过测试指令与其交互。

  1. 遍历 flavors 列表,并确保列表中的每个字符串项都显示在屏幕上。
  2. 使用 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()
    }
}
  1. 使用相同的技术来验证应用显示文本,验证应用在屏幕上显示正确的总计字符串。搜索屏幕,查找 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()
}

回想一下,下一步按钮在选择项目之前是不会启用的。此测试仅验证屏幕内容,因此最后要测试的是下一步按钮处于禁用状态。

  1. 使用相同的按字符串资源 id 查找节点的方法来查找下一步按钮。但是,不要验证应用是否显示该节点,而是使用 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()
}

最大化测试覆盖率

选择风味屏幕内容测试仅测试单个屏幕的一个方面。您可以编写许多其他测试来提高您的代码覆盖率。在下载解决方案代码之前,尝试自行编写以下测试。

  • 验证开始屏幕内容。
  • 验证汇总屏幕内容。
  • 验证在选择风味屏幕上选择选项后,下一步按钮处于启用状态。

在编写测试时,请记住可能有助于减少编写代码量的任何辅助函数!

7. 获取解决方案代码

要下载完成的 Codelab 代码,您可以使用此 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 应用时,请记住同时编写测试和您的功能代码!