Android предоставляет множество инструментов и API, которые помогут вам создавать тесты для разных размеров экрана и окон.
Девицеконфигуратионоверрайд
Составной элемент DeviceConfigurationOverride
позволяет переопределить атрибуты конфигурации для проверки нескольких размеров экрана и окон в макетах Compose. Переопределение ForcedSize
подходит для любого макета в доступном пространстве, что позволяет запускать любой тест пользовательского интерфейса на экране любого размера. Например, вы можете использовать небольшой форм-фактор телефона для запуска всех тестов пользовательского интерфейса, включая тесты пользовательского интерфейса для больших телефонов, складных устройств и планшетов.
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
) {
MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
}
Кроме того, вы можете использовать эту компоновку для установки масштаба шрифта, тем и других свойств, которые вы, возможно, захотите протестировать на окнах разных размеров.
Робоэлектрик
Используйте Robolectric для локального запуска тестов пользовательского интерфейса Compose или View на JVM — никаких устройств или эмуляторов не требуется. Помимо других полезных свойств, вы можете настроить Robolectric на использование определенных размеров экрана.
В следующем примере из раздела «Сейчас в Android » Robolectric настроен на эмуляцию экрана размером 1000x1000 dp с разрешением 480 dpi:
@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 { ... }
Вы также можете установить квалификаторы из тела теста, как это сделано в этом фрагменте примера « Сейчас в Android» :
val (width, height, dpi) = ...
// Set qualifiers from specs.
RuntimeEnvironment.setQualifiers("w${width}dp-h${height}dp-${dpi}dpi")
Обратите внимание, что RuntimeEnvironment.setQualifiers()
обновляет ресурсы системы и приложения новой конфигурацией, но не запускает никаких действий над активными действиями или другими компонентами.
Дополнительную информацию можно прочитать в документации по настройке устройства Robolectric.
Устройства, управляемые Gradle
Плагин Android Gradle для устройств под управлением Gradle (GMD) позволяет вам определять спецификации эмуляторов и реальных устройств, на которых выполняются ваши инструментальные тесты. Создайте спецификации для устройств с экранами разных размеров, чтобы реализовать стратегию тестирования, при которой определенные тесты необходимо запускать на экранах определенных размеров. Используя 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"
}
}
}
}
}
Вы можете найти несколько примеров GMD в проекте тестовых образцов .
Тестовая лаборатория Firebase
Используйте Firebase Test Lab (FTL) или аналогичный сервис фермы устройств, чтобы запускать тесты на конкретных реальных устройствах, к которым у вас может не быть доступа, например складных устройствах или планшетах разных размеров. Firebase Test Lab — платная услуга с бесплатным уровнем . FTL также поддерживает запуск тестов на эмуляторах. Эти услуги повышают надежность и скорость инструментального тестирования, поскольку позволяют заране�� подготовить устройства и эмуляторы.
Сведения об использовании FTL с GMD см. в разделе Масштабирование тестов с помощью устройств, управляемых Gradle .
Тестовая фильтрация с помощью средства запуска тестов
Оптимальная стратегия тестирования не должна проверять одно и то же дважды, поэтому большинство ваших UI-тестов не нужно запускать на нескольких устройствах. Обычно вы фильтруете свои тесты пользовательского интерфейса, запуская все или большинство из них на форм-факторе телефона и только часть на устройствах с разными размерами экрана.
Вы можете аннотировать определенные тесты для запуска только на определенных устройствах, а затем передать аргумент AndroidJUnitRunner с помощью команды, запускающей тесты.
Например, вы можете создавать разные аннотации:
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 Device (см. следующий раздел) также может фильтровать тесты, используя свойства устройства.
Устройство для приготовления эспрессо
Используйте Espresso Device для выполнения действий на эмуляторах в тестах с использованием инструментальных ��ест��в ��юбого ��и��а, вклю��а�� тесты Espresso, Compose или UI Automator. Эти действия могут включать настройку размера экрана или переключение состояний или положений складывания. Например, вы можете управлять складным эмулятором и перевести его в настольный режим. Espresso Device также содержит правила и аннотации 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 все еще находится на стадии альфа-версии и имеет следующие требования:
- Плагин Android Gradle 8.3 или выше
- Эмулятор Android 33.1.10 или выше
- Виртуальное устройство Android с API уровня 24 или выше.
Фильтровать тесты
Espresso Device может считывать свойства подключенных устройств, чтобы вы могли фильтровать тесты с помощью аннотаций . Если аннотированные требования не выполняются, тесты пропускаются.
Аннотация RequiresDeviceMode
Аннотацию 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()))
}
}
ТребуетсяОтобразить аннотацию
Аннотация 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.
}
}
StateRestoreTester
Класс StateRestorationTester
используется для проверки восстановления состояния составных компонентов без воссоздания действий. Это делает тесты более быстрыми и надежными, поскольку воссоздание активности — это сложный процесс с несколькими механизмами синхронизации:
@Test
fun compactDevice_selectedEmailEmailRetained_afterConfigChange() {
val stateRestorationTester = StateRestorationTester(composeTestRule)
// Set content through the StateRestorationTester object.
stateRestorationTester.setContent {
MyApp()
}
// Simulate a config change.
stateRestorationTester.emulateSavedInstanceStateRestore()
}
Библиотека тестирования окон
Библиотека тестирования окон содержит утилиты, которые помогут вам писать тесты, основанные на функциях, связанных с управлением окнами, или проверяющие их, такие как внедрение действий или складные функции. Артефакт доступен через репозиторий 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
в центре экрана, а затем проверяется, соответствует ли макет ожидаемому:
Сочинить
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 .
Дополнительные ресурсы
Документация
- Рекомендации по обеспечению качества приложений для большого экрана
- Тестируйте приложения на Android
- Тестирование макета Compose
Образцы
- Пример оконного менеджера
- Образцы устройств для приготовления эспрессо
- Теперь в Android
- Использует тестирование скриншотов для проверки разных размеров экрана.
Кодлабы