Android מספקת מגוון כלים וממשקי API שיכולים לעזור לכם ליצור בדיקות לגדלים שונים של מסכים וחלונות.
DeviceConfigurationOverride
רכיב ה-Composable DeviceConfigurationOverride
מאפשר לשנות מאפייני הגדרה כדי לבדוק פריסות של Compose בגדלים שונים של מסכים וחלונות. ההחלפה ForcedSize
מתאימה לכל פריסה במקום הפנוי,
מה שמאפשר להריץ כל בדיקת ממשק משתמש בכל גודל מסך. לדוגמה, אפשר להשתמש בטלפון קטן כדי להריץ את כל בדיקות ממשק המשתמש, כולל בדיקות ממשק משתמש לטלפונים גדולים, לטלפונים מתקפלים ולטאבלטים.
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
) {
MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
}

בנוסף, אפשר להשתמש ב-composable הזה כדי להגדיר את קנה המידה של הגופן, את העיצובים ומאפיינים אחרים שרוצים לבדוק בגדלים שונים של חלונות.
Robolectric
אפשר להשתמש ב-Robolectric כדי להריץ בדיקות של ממשקי משתמש מבוססי-Compose או מבוססי-תצוגה ב-JVM באופן מקומי – לא נדרשים מכשירים או אמולטורים. אפשר להגדיר את Robolectric כך שישתמש בגדלי מסך ספציפיים, בין מאפיינים שימושיים אחרים.
@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
תוסף Android Gradle Gradle-managed devices (GMD) מאפשר להגדיר את המפרטים של האמולטורים והמכשירים האמיתיים שבהם מופעלות הבדיקות instrumented. יצירת מפרטים למכשירים עם גדלים שונים של מסכים כדי להטמיע אסטרטגיית בדיקה שבה בדיקות מסוימות צריכות להתבצע בגדלים מסוימים של מסכים. שימוש ב-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 בפרויקט testing-samples.
Firebase Test Lab
אפשר להשתמש ב-Firebase Test Lab (FTL) או בשירות דומה של חוות מכשירים כדי להריץ את הבדיקות במכשירים אמיתיים ספציפיים שאולי אין לכם גישה אליהם, כמו מכשירים מתקפלים או טאבלטים בגדלים שונים. Firebase Test Lab הוא שירות בתשלום עם רמת שימוש ללא תשלום. ב-FTL יש גם תמיכה בהרצת בדיקות באמולטורים. השירותים האלה משפרים את המהימנות והמהירות של בדיקות עם מכשור, כי הם יכולים להקצות מכשירים ואמולטורים מראש.
מידע על שימוש ב-FTL עם GMD זמין במאמר הגדלת היקף הבדיקות באמצעות מכשירים שמנוהלים על ידי Gradle.
בדיקת הסינון באמצעות כלי ההרצה של הבדיקות
אסטרטגיית בדיקה אופטימלית לא צריכה לאמת את אותו הדבר פעמיים, ולכן רוב בדיקות ממשק המשתמש לא צריכות לפעול בכמה מכשירים. בדרך כלל, מסננים את בדיקות ממשק המשתמש על ידי הפעלת כולן או רובן בגורם צורה של טלפון, ורק קבוצת משנה במכשירים עם גדלי מסך שונים.
אפשר להוסיף הערות לבדיקות מסוימות כדי שהן יופעלו רק במכשירים מסוימים, ואז להעביר ארגומנט ל-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 Plugin מגרסה 8.3 ואילך
- Android Emulator מגרסה 33.1.10 ואילך
- מכשיר וירטואלי של Android עם API ברמה 24 ומעלה
סינון בדיקות
מכשיר Espresso יכול לקרוא את המאפיינים של מכשירים מחוברים כדי לאפשר לכם לסנן בדיקות באמצעות הערות. אם הדרישות עם ההערות לא מתקיימות, המערכת מדלגת על הבדיקות.
נדרשת הערה מסוג 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.
}
}
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 Testing
ספריית Window Testing מכילה כלי עזר שיעזרו לכם לכתוב בדיקות שמסתמכות על תכונות שקשורות לניהול חלונות או בודקות אותן, כמו הטמעת פעילות או תכונות של מכשירים מתקפלים. הארטיפקט זמין דרך מאגר Maven של Google.
לדוגמה, אפשר להשתמש בפונקציה 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.
מקורות מידע נוספים
מסמכים
טעימות
- דוגמה ל-WindowManager
- דוגמאות למכשירי אספרסו
- Now In Android
- משתמש בבדיקות צילומי מסך כדי לאמת גדלים שונים של מסכים
Codelabs