Android มีเครื่องมือและ API มากมายที่จะช่วยคุณสร้างการทดสอบสำหรับหน้าจอและขนาดหน้าต่างต่างๆ
DeviceConfigurationOverride
Composable 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.
}

นอกจากนี้ คุณยังใช้ Composable นี้เพื่อตั้งค่าขนาดแบบอักษร ธีม และพร็อพเพอร์ตี้อื่นๆ ที่อาจต้องการทดสอบในขนาดหน้าต่างต่างๆ ได้ด้วย
Robolectric
ใช้ Robolectric เพื่อเรียกใช้การทดสอบ UI ที่อิงตาม Compose หรือ View ใน JVM ในเครื่อง โดยไม่ต้องใช้อุปกรณ์หรือโปรแกรมจำลอง คุณกำหนดค่า Robolectric ให้ใช้ขนาดหน้าจอที่เฉพาะเจาะจงได้ รวมถึงพร็อพเพอร์ตี้อื่นๆ ที่มีประโยชน์
ในตัวอย่างต่อไปนี้จาก Now in 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 { ... }
คุณยังตั้งค่าตัวระบุจากเนื้อหาการทดสอบได้เช่นเดียวกับในข้อมูลโค้ดนี้จากตัวอย่าง 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 (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 หลายรายการได้ในโปรเจ็กต์ testing-samples
Firebase Test Lab
ใช้ Firebase Test Lab (FTL) หรือบริการฟาร์มอุปกรณ์ที่คล้ายกันเพื่อเรียกใช้การทดสอบในอุปกรณ์จริงที่เฉพาะเจาะจงซึ่งคุณอาจไม่มีสิทธิ์เข้าถึง เช่น อุปกรณ์พับได้หรือแท็บเล็ตขนาดต่างๆ Firebase Test Lab เป็นบริการแบบชำระเงินที่มีรุ่นฟรี นอกจากนี้ FTL ยังรองรับการทดสอบในโปรแกรมจำลองด้วย บริการเหล่านี้ช่วยปรับปรุงความน่าเชื่อถือและความเร็วของการทดสอบที่ใช้เครื่องมือเนื่องจาก สามารถจัดสรรอุปกรณ์และโปรแกรมจำลองล่วงหน้าได้
ดูข้อมูลเกี่ยวกับการใช้ FTL กับ GMD ได้ที่ขยายขนาดการทดสอบด้วย อุปกรณ์ที่จัดการโดย Gradle
ทดสอบการกรองด้วยโปรแกรมเรียกใช้การทดสอบ
กลยุทธ์การทดสอบที่เหมาะสมไม่ควรยืนยันสิ่งเดียวกัน 2 ครั้ง ดังนั้นการทดสอบ 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 ขึ้นไป
- อุปกรณ์เสมือน 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 annotation
คำอธิบายประกอบ 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()
}
ไลบรารีการทดสอบหน้าต่าง
ไลบรารีการทดสอบหน้าต่างมีเครื่องมือที่จะช่วยคุณเขียนการทดสอบที่อิงตามหรือยืนยันฟีเจอร์ที่เกี่ยวข้องกับการจัดการหน้าต่าง เช่น การฝังกิจกรรมหรือฟีเจอร์ที่พับได้ อาร์ติแฟกต์พร้อมให้บริการผ่านที่เก็บ Maven ของ Google
เช่น คุณสามารถใช้ฟังก์ชัน FoldingFeature()
เพื่อสร้างFoldingFeature
ที่กำหนดเอง ซึ่งคุณสามารถใช้ในตัวอย่างการเขียน ใน Java ให้ใช้ฟังก์ชัน createFoldingFeature()
ในตัวอย่างการเขียน คุณอาจใช้ FoldingFeature
ในลักษณะต่อไปนี้
@Preview(showBackground = true, widthDp = 480, heightDp = 480)
@Composable private fun FoldablePreview() =
MyApplicationTheme {
ExampleScreen(
displayFeatures = listOf(FoldingFeature(Rect(0, 240, 480, 240)))
)
}
นอกจากนี้ คุณยังจำลองฟีเจอร์การแสดงผลในการทดสอบ UI ได้โดยใช้ฟังก์ชัน
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