使用 Espresso Device API 测试屏幕配置更改

当设备经历常见的配置变更(例如旋转和屏幕展开)时,使用 Espresso 设备 API 测试您的应用。Espresso 设备 API 是推荐的工具,可用于在 Jetpack Compose 测试规则之外执行设备级操作。如果您是首次为 Jetpack Compose 编写界面测试,请参阅测试 Compose 布局

借助 Espresso 设备 API,您可以在虚拟设备上触发配置更改并同步执行测试,这样一次只会发生一个界面操作或断言,测试结果也会更可靠。如果您不熟悉如何使用 Espresso 编写界面测试,请参阅其文档

如需使用 Espresso 设备 API,您需要满足以下条件:

  • Android Studio Iguana 或更高版本
  • Android Gradle 插件 8.3 或更高版本
  • Android 模拟器 33.1.10 或更高版本
  • 运行 API 级别 24 或更高级别的 Android 虚拟设备

为 Espresso 设备 API 设置项目

如需设置项目以使其支持 Espresso 设备 API,请执行以下操作:

  1. 如需让测试将命令传递给测试设备,请将所需的网络权限添加到 androidTest 源代码集中的清单文件:

      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    

    如果您的测试以 Android 17(API 级别 37)或更高版本为目标平台,您还必须声明 ACCESS_LOCAL_NETWORK 权限:

      <uses-permission android:name="android.permission.ACCESS_LOCAL_NETWORK" />
    
  2. gradle.properties 文件中启用 enableEmulatorControl 实验性标志:

      android.experimental.androidTest.enableEmulatorControl=true
    
  3. 在模块级 build 脚本中启用 emulatorControl 选项:

    Kotlin

      testOptions {
        emulatorControl {
          enable = true
        }
      }
      

    Groovy

      testOptions {
        emulatorControl {
          enable = true
        }
      }
      
  4. 在模块级 build 脚本中,将 Espresso 设备库导入到您的项目中:

    Kotlin

    dependencies {
      androidTestImplementation("androidx.test.espresso:espresso-device:1.1.0")
    }

    Groovy

    dependencies {
      androidTestImplementation 'androidx.test.espresso:espresso-device:1.1.0'
    }

针对常见配置变更进行测试

Espresso 设备 API 具有多种屏幕方向和可折叠状态,可用于触发设备配置更改。以下示例展示了如何使用 Compose 测试规则触发这些设备状态并验证由此产生的界面变化。

针对屏幕旋转进行测试

如需测试屏幕旋转,您可以使用 ScreenOrientationRule 类在测试期间定义设备屏幕方向。

以下示例展示了如何测试当设备屏幕旋转时应用会发生什么情况:

  1. 首先,定义您的 Compose 测试规则,并使用 ScreenOrientationRule 类将设备设置为一致的初始状态(例如竖屏模式):

    import androidx.compose.ui.test.assertIsDisplayed
    import androidx.compose.ui.test.assertDoesNotExist
    import androidx.compose.ui.test.junit4.createComposeRule
    import androidx.compose.ui.test.onNodeWithTag
    import androidx.test.espresso.device.EspressoDevice.onDevice
    import androidx.test.espresso.device.action.ScreenOrientation
    import androidx.test.espresso.device.rules.ScreenOrientationRule
    import org.junit.Rule
    import org.junit.Test
    
    class MyConfigurationTest {
    
        // 1. Define the Compose test rule
        @get:Rule
        val composeTestRule = createComposeRule()
    
        // 2. Define the Espresso Device rule for a consistent starting state
        @get:Rule
        val screenOrientationRule = ScreenOrientationRule(ScreenOrientation.PORTRAIT)
    }
    

    如果您的测试以 Android 17(API 级别 37)或更高版本为目标平台,则 Espresso 设备 API 需要 ACCESS_LOCAL_NETWORK 权限。您必须确保在 ScreenOrientationRule 规则运行之前授予此权限。使用 JUnit 的 RuleChain 先运行 GrantPermissionRule 规则:

    import androidx.test.rule.GrantPermissionRule
    import org.junit.rules.RuleChain
    
    class MyConfigurationTest {
        val grantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_LOCAL_NETWORK)
        val composeTestRule = createComposeRule()
        val screenOrientationRule = ScreenOrientationRule(ScreenOrientation.PORTRAIT)
    
        @get:Rule
        val chain = RuleChain
            .outerRule(grantPermissionRule)
            .around(composeTestRule)
            .around(screenOrientationRule)
    }
    
  2. 创建一项测试,该测试会在执行期间将设备设置为横向屏幕方向:

    @Test
    fun myRotationTest() {
      ...
      // Sets the device to landscape orientation during test execution.
      onDevice().setScreenOrientation(ScreenOrientation.LANDSCAPE)
      ...
    }
    
  3. 屏幕旋转后,使用 composeTestRule 检查您的可组合项是否按预期适应新状态。

    @Test
    fun myRotationTest() {
      ...
      // Sets the device to landscape orientation during test execution.
      onDevice().setScreenOrientation(ScreenOrientation.LANDSCAPE)
      composeTestRule.onNodeWithTag("NavRail").assertIsDisplayed()
      composeTestRule.onNodeWithTag("BottomBar").assertDoesNotExist()
    }
    

针对屏幕展开进行测试

以下示例展示了如何测试当应用在可折叠设备上运行时,如果屏幕展开,应用会发生什么情况:

  1. 首先,通过调用 onDevice().setClosedMode() 在设备处于折叠状态时进行测试。确保可组合项能够适应紧凑型屏幕宽度。

    @Test
    fun myUnfoldedTest() {
      onDevice().setClosedMode()
      composeTestRule.onNodeWithTag("BottomBar").assertIsDisplayed()
      composeTestRule.onNodeWithTag("NavRail").assertDoesNotExist()
      ...
    }
    
  2. 如需转换到完全展开状态,请调用 onDevice().setFlatMode()。检查可组合项是否适应扩展后的尺寸类。

    @Test
    fun myUnfoldedTest() {
      onDevice().setClosedMode()
      ...
      onDevice().setFlatMode()
      composeTestRule.onNodeWithTag("NavRail").assertIsDisplayed()
      composeTestRule.onNodeWithTag("BottomBar").assertDoesNotExist()
    }
    

指定测试所需的设备

如果您在不可折叠的设备上运行执行折叠操作的测试,测试很可能会失败。如需仅执行与正在运行的设备相关的测试,请使用 @RequiresDeviceMode 注释。测试运行程序会自动跳过在不支持所测试配置的设备上运行测试。您可以将设备要求规则添加到每个测试或整个测试类。

例如,如需指定测试仅应在支持展开为扁平配置的设备上运行,请将以下 @RequiresDeviceMode 代码添加到测试中:

@Test
@RequiresDeviceMode(mode = FLAT)
fun myUnfoldedTest() {
  ...
}