Android는 다양한 화면 및 창 크기에 맞는 테스트를 만드는 데 도움이 되는 다양한 도구와 API를 제공합니다.
DeviceConfigurationOverride
DeviceConfigurationOverride
컴포저블을 사용하면 구성 속성을 재정의하여 Compose 레이아웃에서 여러 화면 및 창 크기를 테스트할 수 있습니다. ForcedSize
재정의는 사용 가능한 공간에 모든 레이아웃을 맞추므로 모든 화면 크기에서 UI 테스트를 실행할 수 있습니다. 예를 들어 소형 휴대전화 폼 팩터를 사용하여 대형 스마트폰, 폴더블, 태블릿의 UI 테스트를 포함한 모든 UI 테스트를 실행할 수 있습니다.
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
) {
MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
}
또한 이 컴포저블을 사용하여 다양한 창 크기에서 테스트할 글꼴 크기, 테마, 기타 속성을 설정할 수 있습니다.
Robolectric
Robolectric을 사용하여 JVM에서 Compose 또는 뷰 기반 UI 테스트를 로컬로 실행합니다. 기기나 에뮬레이터가 필요하지 않습니다. Robolectric이 다른 유용한 속성 중에서 특정 화면 크기를 사용하도록 구성할 수 있습니다.
Now in Android의 다음 예에서 Robolectric은 해상도가 480dpi인 1000x1000dp 화면 크기를 에뮬레이션하도록 구성되어 있습니다.
@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 플러그인을 사용하면 계측된 테스트가 실행되는 에뮬레이터 및 실제 기기의 사양을 정의할 수 있습니다. 특정 테스트를 특정 화면 크기에서 실행해야 하는 테스트 전략을 구현하기 위해 화면 크기가 다른 기기의 사양을 만듭니다. 지속적 통합(CI)과 함께 GMD를 사용하면 필요할 때 적절한 테스트가 실행되도록 하고, 에뮬레이터를 프로비저닝 및 실행하고, 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 Test Lab
Firebase Test Lab(FTL) 또는 유사한 기기 농장 서비스를 사용하여 액세스할 수 없는 특정 실제 기기(예: 폴더블, 다양한 크기의 태블릿)에서 테스트를 실행합니다. Firebase Test Lab은 무료 등급이 있는 유료 서비스입니다. FTL은 에뮬레이터에서 테스트 실행도 지원합니다. 이러한 서비스는 기기와 에뮬레이터를 미리 프로비저닝할 수 있으므로 계측 테스트의 안정성과 속도를 개선합니다.
GMD에서 FTL을 사용하는 방법에 관한 자세한 내용은 Gradle 관리 기기로 테스트 확장을 참고하세요.
테스트 실행기로 테스트 필터링
최적의 테스트 전략은 동일한 항목을 두 번 확인해서는 안 되므로 대부분의 UI 테스트는 여러 기기에서 실행할 필요가 없습니다. 일반적으로 UI 테스트의 일부 또는 전부를 휴대전화 폼 팩터에서 실행하고 화면 크기가 다른 기기에서는 하위 집합만 실행하여 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 기기
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 Emulator 33.1.10 이상
- API 수준 24 이상을 실행하는 Android Virtual Device
테스트 필터링
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 주석
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
클래스는 활동을 다시 만들지 않고 컴포저블 구성요소의 상태 복원을 테스트하는 데 사용됩니다. 이렇게 하면 활동 재생성이 여러 동기화 메커니즘이 있는 복잡한 프로세스이므로 테스트가 더 빠르고 안정적으로 실행됩니다.
@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 테스트 라이브러리
창 테스트 라이브러리에는 활동 삽입 또는 폴더블 기능과 같은 창 관리와 관련된 기능을 사용하거나 확인하는 테스트를 작성하는 데 도움이 되는 유틸리티가 포함되어 있습니다. 아티팩트는 Google Maven 저장소를 통해 사용할 수 있습니다.
예를 들어 FoldingFeature()
함수를 사용하여 맞춤 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()
함수를 사용하여 UI 테스트에서 디스플레이 기능을 에뮬레이션할 수 있습니다.
다음 예에서는 화면 중앙에 HALF_OPENED
수직 힌지가 있는 FoldingFeature
를 시뮬레이션한 다음 레이아웃이 예상대로 작동하는지 확인합니다.
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
- 스크린샷 테스트를 사용하여 다양한 화면 크기 확인
Codelab