Android มีเครื่องมือและ API มากมายที่สามารถช่วยคุณสร้างการทดสอบสำหรับ หน้าจอและหน้าต่างขนาดต่างๆ
DeviceConfigurationOverride
คอมโพสิเบิล DeviceConfigurationOverride
ช่วยให้คุณลบล้างแอตทริบิวต์การกําหนดค่าเพื่อทดสอบหน้าจอและหน้าต่างหลายขนาดในเลย์เอาต์คอมโพสิเบิลได้ การลบล้าง 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 แบบเขียนหรือแบบอิงตามมุมมองใน 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
อุปกรณ์ที่จัดการโดย 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"
}
}
}
}
}
คุณดูตัวอย่าง GMD หลายรายการได้ในโปรเจ็กต์ testing-samples
Firebase Test Lab
ใช้ Firebase Test Lab (FTL) หรือบริการฟาร์มอุปกรณ์ที่คล้ายกันเพื่อเรียกใช้ การทดสอบในอุปกรณ์จริงบางอย่างที่คุณอาจเข้าถึงไม่ได้ เช่น อุปกรณ์แบบพับได้หรือแท็บเล็ตขนาดต่างๆ Firebase Test Lab เป็นผลิตภัณฑ์แบบมีค่าใช้จ่าย ด้วยรุ่นฟรี FTL ยังรองรับการเรียกใช้การทดสอบในโปรแกรมจำลองด้วย บริการเหล่านี้ช่วยเพิ่มความน่าเชื่อถือและความเร็วในการทดสอบที่มีเครื่องมือวัดผล เนื่องจากสามารถจัดสรรอุปกรณ์และโปรแกรมจำลองล่วงหน้าได้
ดูข้อมูลเกี่ยวกับการใช้ FTL กับ GMD ได้ที่ปรับขนาดการทดสอบด้วยอุปกรณ์ที่จัดการโดย Gradle
ทดสอบการกรองด้วยโปรแกรมรันทดสอบ
กลยุทธ์การทดสอบที่ดีที่สุดไม่ควรยืนยันสิ่งเดียวกันซ้ำ ดังนั้นการทดสอบ 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 (ดูส่วนถัดไป) สามารถกรองการทดสอบโดยใช้พร็อพเพอร์ตี้อุปกรณ์ได้ด้วย
อุปกรณ์เอสเพรสโซ
ใช้ Espresso Device เพื่อดำเนินการกับโปรแกรมจำลองในการทดสอบโดยใช้การทดสอบที่มีเครื่องมือวัดผลประเภทใดก็ได้ ซึ่งรวมถึงการทดสอบ 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 ยังอยู่ในขั้นอัลฟ่าและมีคุณสมบัติดังต่อไปนี้ ข้อกำหนด
- ปลั๊กอิน Android Gradle 8.3 ขึ้นไป
- โปรแกรมจำลอง Android 33.1.10 ขึ้นไป
- อุปกรณ์เสมือน Android ที่ใช้ API ระดับ 24 ขึ้นไป
กรองการทดสอบ
อุปกรณ์ Espresso สามารถอ่านคุณสมบัติของอุปกรณ์ที่เชื่อมต่อเพื่อให้คุณทำสิ่งต่อไปนี้ได้ กรองการทดสอบโดยใช้คำอธิบายประกอบ หากไม่เป็นไปตามข้อกำหนดที่มีคำอธิบายประกอบ ระบบจะข้ามการทดสอบ
ต้องใช้คำอธิบายประกอบ DeviceMode
คุณใช้คำอธิบายประกอบ 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()
}
ไลบรารีการทดสอบหน้าต่าง
ไลบรารีการทดสอบหน้าต่างประกอบด้วยยูทิลิตีที่จะช่วยคุณเขียนการทดสอบที่อาศัยหรือยืนยันฟีเจอร์ที่เกี่ยวข้องกับการจัดการหน้าต่าง เช่น การฝังกิจกรรมหรือฟีเจอร์แบบพับได้ อาร์ติแฟกต์มีให้บริการผ่านที่เก็บ 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
- ตัวอย่างอุปกรณ์ Espresso
- พร้อมใช้งานแล้วใน Android
- ใช้การทดสอบภาพหน้าจอเพื่อยืนยันหน้าจอขนาดต่างๆ
Codelabs