Android มีเครื่องมือและ API มากมายที่สามารถช่วยคุณสร้างการทดสอบสำหรับ หน้าจอและหน้าต่างขนาดต่างๆ
ลบล้างการกำหนดค่าอุปกรณ์
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 เพื่อเรียกใช้การทดสอบ UI แบบเขียนหรือแบบอิงตามการดูใน JVM ในเครื่อง - ไม่ต้องใช้อุปกรณ์หรือโปรแกรมจำลอง คุณสามารถกำหนดค่า ใช้ขนาดหน้าจอที่เจาะจง รวมถึงคุณสมบัติอื่นๆ ที่เป็นประโยชน์
ในตัวอย่างต่อไปนี้จาก 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-ตัวอย่าง
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 (ดูส่วนถัดไป) ยังสามารถกรองการทดสอบโดยใช้ พร็อพเพอร์ตี้ของอุปกรณ์
อุปกรณ์เอสเพรสโซ
ใช้อุปกรณ์ Espresso เพื่อดำเนินการกับโปรแกรมจำลองในการทดสอบโดยใช้ ประเภทการทดสอบที่มีการวัดคุม ได้แก่ การทดสอบ 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()
}
ไลบรารีการทดสอบหน้าต่าง
ไลบรารีการทดสอบ Window มียูทิลิตีที่จะช่วยคุณเขียนการทดสอบที่อาศัย เปิดหรือยืนยันฟีเจอร์ที่เกี่ยวข้องกับการจัดการหน้าต่าง เช่น กิจกรรม การฝังหรือฟีเจอร์แบบพับได้ อาร์ติแฟกต์พร้อมใช้งานผ่าน ที่เก็บ Maven
ตัวอย่างเช่น คุณสามารถใช้ฟังก์ชัน FoldingFeature()
เพื่อสร้าง
FoldingFeature
ที่กำหนดเอง ซึ่งคุณสามารถใช้ในตัวอย่างการเขียนได้ ใน 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)))
)
}
นอกจากนี้ คุณสามารถจำลองฟีเจอร์การแสดงผลในการทดสอบ 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
- ใช้การทดสอบภาพหน้าจอเพื่อยืนยันหน้าจอขนาดต่างๆ
Codelab