Android 提供了各种工具和 API,可帮助您为 不同的屏幕尺寸和窗口大小
DeviceConfigurationOverride
的陪同者借助 DeviceConfigurationOverride
可组合项,您可以替换
用于在 Compose 中测试多种屏幕尺寸和窗口大小的配置属性
布局。ForcedSize
替换项适合可用空间中的任何布局,
让您可以运行任何
针对任何屏幕尺寸进行界面测试。例如,您可以使用小屏幕手机
来运行所有界面测试,包括针对大手机、可折叠设备和
平板电脑
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
) {
MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
}
<ph type="x-smartling-placeholder">
此外,您还可以使用此可组合项设置字体大小、主题和其他 您可能想针对不同窗口大小测试的属性。
Robolectric
使用 Robolectric 在 JVM 上运行 Compose 或基于视图的界面测试 本地 - 无需设备或模拟器。您可以配置 Robolectric 支持使用特定屏幕尺寸以及其他实用属性。
在 Now in Android 的以下示例中,Robolectric 配置 以 480 dpi 的分辨率模拟 1000x1000 dp 的屏幕尺寸:
@RunWith(RobolectricTestRunner::class)
// Configure Robolectric to use a very large screen size that can fit all of the test sizes.
// This allows enough room to render the content under test without clipping or scaling.
@Config(qualifiers = "w1000dp-h1000dp-480dpi")
class NiaAppScreenSizesScreenshotTests { ... }
您还可以在测试正文中设置限定符,如以下代码段所示 Now in Android 示例:
val (width, height, dpi) = ...
// Set qualifiers from specs.
RuntimeEnvironment.setQualifiers("w${width}dp-h${height}dp-${dpi}dpi")
请注意,RuntimeEnvironment.setQualifiers()
会更新系统,
具有新配置的应用资源,但不会触发任何操作
或有效性活动或其他组件
如需了解详情,请参阅 Robolectric 设备配置文档。
Gradle 管理的设备
Gradle 管理的设备 (GMD) Android Gradle 插件 您可以定义模拟器和真实设备的规格 插桩测试所运行的测试。为符合以下条件的设备创建规范: 不同的屏幕尺寸来实施测试策略,其中某些测试必须 可在特定屏幕尺寸上运行将 GMD 与持续集成结合使用 (CI),您可以确保在需要时运行适当的测试, 预配和启动模拟器,并简化 CI 设置。
android {
testOptions {
managedDevices {
devices {
// Run with ./gradlew nexusOneApi30DebugAndroidTest.
nexusOneApi30(com.android.build.api.dsl.ManagedVirtualDevice) {
device = "Nexus One"
apiLevel = 30
// Use the AOSP ATD image for better emulator performance
systemImageSource = "aosp-atd"
}
// Run with ./gradlew foldApi34DebugAndroidTest.
foldApi34(com.android.build.api.dsl.ManagedVirtualDevice) {
device = "Pixel Fold"
apiLevel = 34
systemImageSource = "aosp-atd"
}
}
}
}
}
您可以在 testing-samples 项目中找到多个 GMD 示例。
Firebase 测试实验室
使用 Firebase Test Lab (FTL) 或类似的设备场服务来运行您的 在您可能无权访问的特定真实设备上进行测试,例如 各种尺寸的可折叠设备或平板电脑Firebase 测试实验室是付费的 提供一项免费层级的服务。FTL 还支持在模拟器上运行测试。 这些服务可以提高插桩测试的可靠性和速度,因为 他们可以提前配置设备和模拟器。
如需了解如何将 FTL 与 GMD 搭配使用,请参阅使用 Gradle 管理的设备。
使用测试运行程序进行测试过滤
最佳测试策略不应该重复验证同一件事, 界面测试不需要在多部设备上运行。通常,您需要过滤界面 方法是在手机外形规格的手机上运行全部或大部分测试, 具有不同屏幕尺寸的设备
您可以为某些测试添加注解,使其仅在特定设备上运行,然后通过测试 使用运行 测试。
例如,您可以创建不同的注释:
annotation class TestExpandedWidth
annotation class TestCompactWidth
并在不同的测试中使用它们:
class MyTestClass {
@Test
@TestExpandedWidth
fun myExample_worksOnTablet() {
...
}
@Test
@TestCompactWidth
fun myExample_worksOnPortraitPhone() {
...
}
}
然后,您可以使用 android.testInstrumentationRunnerArguments.annotation
属性来过滤特定事件。例如,如果你
使用 Gradle 管理的设备:
$ ./gradlew pixelTabletApi30DebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'
如果您不使用 GMD,而是在 CI 上管理模拟器,请先确保 正确的模拟器或设备已就绪并连接,然后传递参数 其中一个 Gradle 命令来运行插桩测试:
$ ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'
请注意,Espresso 设备(请参阅下一部分)还可以使用 设备属性。
浓缩咖啡设备
使用 Espresso 设备在使用任意 插桩测试的类型,包括 Espresso、Compose 或 UI Automator 测试。 这些操作可能包括设置屏幕尺寸或切换可折叠设备状态 状态。例如,您可以控制可折叠设备模拟器,并将其设置为 桌面模式Espresso 设备还包含 JUnit 规则和注解, 需要使用特定功能:
@RunWith(AndroidJUnit4::class)
class OnDeviceTest {
@get:Rule(order=1) val activityScenarioRule = activityScenarioRule<MainActivity>()
@get:Rule(order=2) val screenOrientationRule: ScreenOrientationRule =
ScreenOrientationRule(ScreenOrientation.PORTRAIT)
@Test
fun tabletopMode_playerIsDisplayed() {
// Set the device to tabletop mode.
onDevice().setTabletopMode()
onView(withId(R.id.player)).check(matches(isDisplayed()))
}
}
请注意,Espresso Device 仍处于 Alpha 版阶段,具有以下特征 要求:
- Android Gradle 插件 8.3 或更高版本
- Android 模拟器 33.1.10 或更高版本
- 搭载 API 级别 24 或更高级别的 Android 虚拟设备
过滤测试
Espresso 设备可以读取已连接设备的属性,使您能够 使用注解过滤测试。如果不符合标注的要求 这些测试会被跳过
RequireDeviceMode 注解
RequiresDeviceMode
注解可以多次用于指示
仅当所有DeviceMode
值均受支持时才会运行的测试
。
class OnDeviceTest {
...
@Test
@RequiresDeviceMode(TABLETOP)
@RequiresDeviceMode(BOOK)
fun tabletopMode_playerIdDisplayed() {
// Set the device to tabletop mode.
onDevice().setTabletopMode()
onView(withId(R.id.player)).check(matches(isDisplayed()))
}
}
RequireDisplay 注解
借助 RequiresDisplay
注解,您可以指定
使用尺寸类别显示设备屏幕,这些尺寸类定义了维度范围
遵循官方的窗口大小类别。
class OnDeviceTest {
...
@Test
@RequiresDisplay(EXPANDED, COMPACT)
fun myScreen_expandedWidthCompactHeight() {
...
}
}
调整显示屏大小
使用 setDisplaySize()
方法调整屏幕尺寸的大小
。请将该方法与 DisplaySizeRule
结合使用
类,这可确保测试期间所做的任何更改都会在
下一个测试。
@RunWith(AndroidJUnit4::class)
class ResizeDisplayTest {
@get:Rule(order = 1) val activityScenarioRule = activityScenarioRule<MainActivity>()
// Test rule for restoring device to its starting display size when a test case finishes.
@get:Rule(order = 2) val displaySizeRule: DisplaySizeRule = DisplaySizeRule()
@Test
fun resizeWindow_compact() {
onDevice().setDisplaySize(
widthSizeClass = WidthSizeClass.COMPACT,
heightSizeClass = HeightSizeClass.COMPACT
)
// Verify visual attributes or state restoration.
}
}
使用 setDisplaySize()
调整屏幕大小时,不会影响密度
因此如果某个尺寸不适合目标设备,测试
失败并显示 UnsupportedDeviceOperationException
。要阻止测试
请使用 RequiresDisplay
注解将其过滤掉:
@RunWith(AndroidJUnit4::class)
class ResizeDisplayTest {
@get:Rule(order = 1) var activityScenarioRule = activityScenarioRule<MainActivity>()
// Test rule for restoring device to its starting display size when a test case finishes.
@get:Rule(order = 2) var displaySizeRule: DisplaySizeRule = DisplaySizeRule()
/**
* Setting the display size to EXPANDED would fail in small devices, so the [RequiresDisplay]
* annotation prevents this test from being run on devices outside the EXPANDED buckets.
*/
@RequiresDisplay(
widthSizeClass = WidthSizeClassEnum.EXPANDED,
heightSizeClass = HeightSizeClassEnum.EXPANDED
)
@Test
fun resizeWindow_expanded() {
onDevice().setDisplaySize(
widthSizeClass = WidthSizeClass.EXPANDED,
heightSizeClass = HeightSizeClass.EXPANDED
)
// Verify visual attributes or state restoration.
}
}
StateRestorationTester
StateRestorationTester
类用于测试状态恢复
而无需重新创建 activity。这样可以加快测试速度
更可靠,因为 activity 重新创建是一个复杂的过程,需要
同步机制:
@Test
fun compactDevice_selectedEmailEmailRetained_afterConfigChange() {
val stateRestorationTester = StateRestorationTester(composeTestRule)
// Set content through the StateRestorationTester object.
stateRestorationTester.setContent {
MyApp()
}
// Simulate a config change.
stateRestorationTester.emulateSavedInstanceStateRestore()
}
窗口测试库
Window Testing 库包含一些实用程序,可帮助您编写依赖于 启用或验证与窗口管理相关的功能,例如活动 嵌入或可折叠功能。该制品可通过 Google 的 Maven 制品库。
例如,您可以使用 FoldingFeature()
函数来生成
自定义 FoldingFeature
,可在 Compose 预览中使用。在 Java 中
使用 createFoldingFeature()
函数。
在 Compose 预览中,您可以通过以下方式实现 FoldingFeature
:
@Preview(showBackground = true, widthDp = 480, heightDp = 480)
@Composable private fun FoldablePreview() =
MyApplicationTheme {
ExampleScreen(
displayFeatures = listOf(FoldingFeature(Rect(0, 240, 480, 240)))
)
}
此外,您还可以使用
TestWindowLayoutInfo()
函数。
以下示例模拟了 FoldingFeature
HALF_OPENED
设在屏幕中心的垂直合页,然后检查
预期的布局是:
Compose
import androidx.window.layout.FoldingFeature.Orientation.Companion.VERTICAL
import androidx.window.layout.FoldingFeature.State.Companion.HALF_OPENED
import androidx.window.testing.layout.FoldingFeature
import androidx.window.testing.layout.TestWindowLayoutInfo
import androidx.window.testing.layout.WindowLayoutInfoPublisherRule
@RunWith(AndroidJUnit4::class)
class MediaControlsFoldingFeatureTest {
@get:Rule(order=1)
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
@get:Rule(order=2)
val windowLayoutInfoPublisherRule = WindowLayoutInfoPublisherRule()
@Test
fun foldedWithHinge_foldableUiDisplayed() {
composeTestRule.setContent {
MediaPlayerScreen()
}
val hinge = FoldingFeature(
activity = composeTestRule.activity,
state = HALF_OPENED,
orientation = VERTICAL,
size = 2
)
val expected = TestWindowLayoutInfo(listOf(hinge))
windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(expected)
composeTestRule.waitForIdle()
// Verify that the folding feature is detected and media controls shown.
composeTestRule.onNodeWithTag("MEDIA_CONTROLS").assertExists()
}
}
视图
import androidx.window.layout.FoldingFeature.Orientation
import androidx.window.layout.FoldingFeature.State
import androidx.window.testing.layout.FoldingFeature
import androidx.window.testing.layout.TestWindowLayoutInfo
import androidx.window.testing.layout.WindowLayoutInfoPublisherRule
@RunWith(AndroidJUnit4::class)
class MediaControlsFoldingFeatureTest {
@get:Rule(order=1)
val activityRule = ActivityScenarioRule(MediaPlayerActivity::class.java)
@get:Rule(order=2)
val windowLayoutInfoPublisherRule = WindowLayoutInfoPublisherRule()
@Test
fun foldedWithHinge_foldableUiDisplayed() {
activityRule.scenario.onActivity { activity ->
val feature = FoldingFeature(
activity = activity,
state = State.HALF_OPENED,
orientation = Orientation.VERTICAL)
val expected = TestWindowLayoutInfo(listOf(feature))
windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(expected)
}
// Verify that the folding feature is detected and media controls shown.
onView(withId(R.id.media_controls)).check(matches(isDisplayed()))
}
}
您可以在 WindowManager 项目中找到更多示例。
其他资源
文档
示例
- WindowManager 示例
- Espresso 设备示例
- Now In Android
<ph type="x-smartling-placeholder">
- </ph>
- 使用屏幕截图测试来验证不同的屏幕尺寸
Codelab