UI Automator เป็นเฟรมเวิร์กจาก Google สำหรับการทดสอบ UI อัตโนมัติของแอปพลิเคชัน Android ที่ทำงานในระดับระบบและสามารถโต้ตอบกับองค์ประกอบอินเทอร์เฟซนอกเหนือจากแอปพลิเคชันเดียว ต่างจาก Espresso ตรงที่ UI Automator ไม่ผูกติดกับกระบวนการของแอปพลิเคชันใดโดยเฉพาะ: มันสามารถเปิดไดอะล็อกระบบ แผงการแจ้งเตือน และสลับระหว่างแอปพลิเคชันได้ ตาม Google Android Developers UI Automator ใช้ Accessibility Service มาตรฐานเพื่อเข้าถึง UI ทรีของอุปกรณ์
ประเด็นสำคัญ
UI Automator เป็นเฟรมเวิร์กสำหรับการทดสอบ UI เชิงฟังก์ชันของ Android ที่ทำงานในระดับระบบปฏิบัติการ มันให้ API สำหรับเข้าถึงองค์ประกอบใดๆ บนหน้าจออุปกรณ์ ไม่ว่าองค์ประกอบนั้นจะเป็นของแอปพลิเคชันใด — รวมถึงแถบสถานะระบบ ไดอะล็อกสิทธิ์ หน้าจอหลัก และแอปของบุคคลที่สาม สิ่งนี้ทำให้มันขาดไม่ได้สำหรับการทดสอบสถานการณ์ที่เกินกว่าแอปพลิเคชันเดียว
ในเชิงสถาปัตยกรรม UI Automator ใช้ Accessibility Service — บริการเดียวกับที่ TalkBack, Switch Access และเครื่องมือการเข้าถึงอื่นๆ ใช้ ผ่านบริการนี้ เฟรมเวิร์กจะได้รับ UI คอมโพเนนต์ทรีที่สมบูรณ์ของหน้าจอปัจจุบันและอนุญาตให้ดำเนินการกับองค์ประกอบเหล่านั้น: การแตะ การปัด การป้อนข้อความ และการกดค้าง
UI Automator ปรากฏครั้งแรกใน Android 4.3 (API 18) และตั้งแต่นั้นมาเป็นส่วนหนึ่งของ Android Testing Support Library ในฐานะเครื่องมืออย่างเป็นทางการของ Google สำหรับการทดสอบข้ามแอปพลิเคชัน ใน AndroidX Test มันพร้อมใช้งานเป็นอาร์ติแฟกต์แยกต่างหาก androidx.test.uiautomator:uiautomator เวอร์ชัน 2.3.0 (2024) ซึ่งรองรับ Android ทุกเวอร์ชันตั้งแต่ API 18
หลักการทำงาน: UI Automator อาศัยการสแกน Accessibility ทรีของหน้าจอปัจจุบัน เมื่อเรียกเมธอด findObject(selector) เฟรมเวิร์กจะสำรวจลำดับชั้นของ View ค้นหาองค์ประกอบแรกที่ตรงกับเงื่อนไขของ UiSelector และส่งคืน UiObject — ตัวแทนสำหรับโต้ตอบกับ View จริง
การทดสอบ UI Automator ทั่วไปเริ่มต้นด้วยการรับอินสแตนซ์ของ UiDevice ซึ่งแสดงถึงอุปกรณ์จริง UiDevice มีเมธอดสำหรับค้นหาองค์ประกอบ จัดการการกดปุ่ม (Home, Back, Recent) หมุนหน้าจอ และจับภาพหน้าจอ หลังจากค้นหาองค์ประกอบผ่าน UiSelector แล้ว จะดำเนินการกับ UiObject
ในตัวอย่างด้านล่าง การทดสอบจะเปิดแอป Settings ค้นหารายการ “แบตเตอรี่” ด้วยข้อความและแตะมัน UI Automator ไม่ต้องการการเปิด Activity — มันทำงานกับหน้าจอใดๆ บนอุปกรณ์ รวมถึงแอปของบุคคลที่สาม
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
// เปิดหน้าจอการตั้งค่า
device.pressHome()
device.wait(Until.hasObject(UiSelector().text("การตั้งค่า")), 2000)
// ค้นหารายการ "แบตเตอรี่" และแตะ
val batteryItem = device.findObject(
UiSelector().text("แบตเตอรี่")
)
batteryItem.clickAndWait(Until.newWindow(), 3000)
UiDevice เป็นคลาสหลักสำหรับโต้ตอบกับอุปกรณ์ มันมีเมธอดสำหรับค้นหาองค์ประกอบ จำลองการกดปุ่มฮาร์ดแวร์ (Home, Back, Menu, Volume) จัดการพลังงาน จับภาพหน้าจอ และรอสถานะหน้าจอที่เฉพาะเจาะจง UiDevice ถูกสร้างขึ้นหนึ่งครั้งต่อการทดสอบและนำมาใช้ซ้ำสำหรับการดำเนินการทั้งหมด
UiSelector เป็น API แบบลื่นไหลสำหรับค้นหาองค์ประกอบ UI ต่างจาก Espresso ViewMatchers ตรงที่ UiSelector ไม่ต้องการการคอมไพล์ — เงื่อนไขการค้นหาถูกสร้างขึ้นผ่านลูกโซ่เมธอด: text(), className(), description(), resourceId(), index() หลายเงื่อนไขจะถูกรวมกันโดยอัตโนมัติผ่าน AND เชิงตรรกะ
| เมธอด UiSelector | วัตถุประสงค์ |
|---|---|
| text(String) | ค้นหาตามข้อความที่แน่นอนขององค์ประกอบ |
| textContains(String) | ค้นหาตามการจับคู่ข้อความบางส่วน |
| resourceId(String) | ค้นหาตาม ID ทรัพยากร (เช่น com.example:id/button) |
| className(String) | ค้นหาตามชื่อคลาสของ View |
| description(String) | ค้นหาตาม content-description |
| childSelector(selector) | ค้นหาองค์ประกอบย่อยภายในคอนเทนเนอร์ |
เมื่อมีหลายองค์ประกอบบนหน้าจอที่มีข้อความเดียวกัน UiSelector อนุญาตให้รวมเกณฑ์: ค้นหาคอนเทนเนอร์ตาม ID จากนั้นภายในนั้น — ค้นหาองค์ประกอบตามข้อความและคลาส สิ่งนี้รับประกันการระบุคอมโพเนนต์ที่ต้องการได้อย่างไม่ซ้ำกัน เมธอด childSelector จะจำกัดขอบเขตการค้นหาให้แคบลงเหลือคอนเทนเนอร์ที่ระบุ ทำให้การนำทางใน UI ทรีเร็วขึ้น
val scrollView = device.findObject(
UiSelector().resourceId("android:id/list")
)
// ภายในรายการ ค้นหาองค์ประกอบที่มีข้อความ "Wi-Fi"
val wifiItem = scrollView.findObject(
UiSelector().text("Wi-Fi")
wifiItem.click()
การทดสอบข้ามแอปพลิเคชัน (ระหว่างแอปพลิเคชัน) เป็นคุณสมบัติหลักที่เลือกใช้ UI Automator เฟรมเวิร์กสามารถสลับระหว่างแอป ทดสอบการเข้าสู่ระบบ OAuth ผ่านเบราว์เซอร์ ตรวจสอบไดอะล็อกระบบ (สิทธิ์ ตัวเลือกแอป) และโต้ตอบกับแถบสถานะระบบ แผงการแจ้งเตือน และหน้าจอล็อก
สถานการณ์ทดสอบข้ามแอปทั่วไป: แอปเปิดเบราว์เซอร์สำหรับการอนุญาต OAuth ผู้ใช้ป้อนชื่อผู้ใช้และรหัสผ่าน และเบราว์เซอร์เปลี่ยนเส้นทางกลับไปยังแอป UI Automator สลับระหว่างกระบวนการ ค้นหาฟิลด์ป้อนข้อมูลในเบราว์เซอร์ กรอกข้อมูล และแตะ “ลงชื่อเข้าใช้”
// กำลังรอให้เบราว์เซอร์ปรากฏ
device.wait(Until.hasObject(
UiSelector().packageName("com.android.chrome")
), 5000)
// กำลังค้นหาฟิลด์ป้อนอีเมลในเบราว์เซอร์
val emailField = device.findObject(
UiSelector().className("android.widget.EditText").instance(0)
)
emailField.text = "user@example.com"
UI Automator สามารถตรวจสอบและปิดไดอะล็อกระบบ — สิทธิ์ตำแหน่ง การแจ้งเตือน การเข้าถึงไฟล์ สิ่งนี้สำคัญอย่างยิ่งสำหรับการทดสอบสถานการณ์การเปิดครั้งแรกเมื่อระบบขอสิทธิ์หลายรายการตามลำดับ หากไม่มี UI Automator สถานการณ์เหล่านี้ไม่สามารถทำให้เป็นอัตโนมัติได้เนื่องจากไดอะล็อกระบบไม่ได้เป็นของกระบวนการของแอป
การเลือก ระหว่าง UI Automator และ Espresso ขึ้นอยู่กับสถานการณ์การทดสอบ Espresso ถูกปรับให้เหมาะสมสำหรับการทดสอบแอปเดียวด้วยการซิงโครไนซ์อัตโนมัติและโค้ดพื้นฐานที่น้อยที่สุด UI Automator เหมาะสำหรับสถานการณ์ที่ต้องโต้ตอบกับระบบ เบราว์เซอร์ หรือหลายแอป
| เกณฑ์ | UI Automator | Espresso |
|---|---|---|
| ขอบเขต | ทั้งอุปกรณ์ หลายแอป | แอปเดียว |
| การซิงโครไนซ์ | ด้วยตนเอง (รอ, หยุด) | อัตโนมัติ (Idling Resource) |
| ความเร็ว | ช้ากว่า (เข้าถึงผ่านบริการ) | เร็วกว่า (ทำงานภายในกระบวนการ) |
| UI ระบบ | รองรับ (การแจ้งเตือน, การตั้งค่าด่วน) | ไม่รองรับ |
| ความแม่นยำในการค้นหา | UiSelector ตามแอตทริบิวต์ | ViewMatchers ตามประเภทและลำดับชั้น |
| ความเสถียร | ต่ำกว่า (ขึ้นอยู่กับจังหวะเวลา) | สูงกว่า (รออัตโนมัติ) |
ในทางปฏิบัติ เฟรมเวิร์กเหล่านี้มักใช้ ร่วมกัน: Espresso ครอบคลุมการทดสอบ UI ของแอปหลักด้วยความเสถียรสูง ในขณะที่ UI Automator ถูกนำมาใช้สำหรับสถานการณ์ที่เกินขอบเขตของแอป — การเข้าสู่ระบบ OAuth สิทธิ์ระบบ การทำงานกับ Share Intent การรวมกันนี้ให้ความครอบคลุม UI สูงสุดด้วยต้นทุนการบำรุงรักษาการทดสอบที่น้อยที่สุด
การผสานรวม UI Automator ทำได้โดยเพิ่มการพึ่งพาใน build.gradle เฟรมเวิร์กเป็นส่วนหนึ่งของ AndroidX Test และไม่ต้องการสิทธิ์เพิ่มเติมใน manifest — การเข้าถึง Accessibility Service ถูกกำหนดค่าโดยอัตโนมัติเมื่อเริ่มการทดสอบแบบใช้เครื่องมือ
การกำหนดค่าขั้นต่ำประกอบด้วยอาร์ติแฟกต์ uiautomator และตัวรันการทดสอบมาตรฐาน AndroidJUnitRunner การทดสอบ UI Automator จะอยู่ในไดเรกทอรี src/androidTest และทำงานบนอีมูเลเตอร์หรืออุปกรณ์จริงที่ใช้ Android API 18+
dependencies {
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test:runner:1.6.1")
}
เพื่อรับอินสแตนซ์ UiDevice ให้ใช้ InstrumentationRegistry.getInstrumentation() UiDevice ควรถูกสร้างขึ้นครั้งเดียวในเมธอด setUp() และนำมาใช้ซ้ำในการทดสอบทั้งหมดของคลาสเพื่อประหยัดทรัพยากรอุปกรณ์ สิ่งสำคัญที่ต้องทราบคือ UiDevice ไม่ปลอดภัยต่อเธรด — การดำเนินการทั้งหมดต้องดำเนินการในเธรดเดียวกันของเมธอดทดสอบ การสร้าง UiDevice ใหม่ในแต่ละการทดสอบทำให้เกิดโอเวอร์เฮดและทำให้การทำงานช้าลง ขอแนะนำให้สร้าง UiDevice ครั้งเดียวในเมธอด beforeClass และนำมาใช้ซ้ำสำหรับการทดสอบทั้งหมดของคลาสทดสอบ
ต่างจาก Espresso ตรงที่ UI Automator ไม่มีการซิงโครไนซ์อัตโนมัติ เพื่อรอให้องค์ประกอบปรากฏ ให้ใช้เมธอด UiDevice.wait(condition, timeout) กับออบเจกต์ Until: Until.findObject(selector), Until.hasObject(selector), Until.gone(selector) หากไม่มีการรอที่เหมาะสม การทดสอบจะไม่เสถียรเนื่องจากสภาวะการแข่งขัน — องค์ประกอบอาจยังไม่ปรากฏบนหน้าจอในเวลาที่ค้นหา ขอแนะนำให้ตั้งค่ากำหนดเวลาไม่น้อยกว่า 3–5 วินาทีเพื่อความเสถียร
คำถามที่พบบ่อย
UI Automator ทำงานในระดับ Accessibility Service และสามารถโต้ตอบกับแอปพลิเคชันใดก็ได้ Espresso ทำงานภายในกระบวนการของแอปเดียวและใช้การซิงโครไนซ์อัตโนมัติกับเธรด UI UI Automator เหมาะสำหรับสถานการณ์ข้ามแอป ในขณะที่ Espresso เหมาะสำหรับการทดสอบแอปเดียวที่เสถียร
ใช่ UI Automator ทำงานบนอุปกรณ์ทั้งหมดที่ใช้ Android API 18+ ไม่จำเป็นต้องเข้าถึงรูท — มันใช้ Accessibility Service มาตรฐาน ซึ่งเปิดใช้งานผ่าน Instrumentation เมื่อเริ่มการทดสอบ
UI Automator ใช้ Accessibility Service เพื่อรับ UI คอมโพเนนต์ทรีที่สมบูรณ์ของหน้าจอปัจจุบัน จากนั้น UiSelector จะสำรวจทรีนี้และค้นหาองค์ประกอบตามเกณฑ์ที่ระบุ: ข้อความ คลาส ID content-description หรือการรวมกันของเกณฑ์เหล่านี้
ใช่ เมธอด UiDevice.takeScreenshot(storePath) ช่วยให้จับภาพหน้าจอปัจจุบันและบันทึกลงในไฟล์ได้ สิ่งนี้มีประโยชน์สำหรับการดีบัก: เมื่อการทดสอบล้มเหลว คุณสามารถบันทึกภาพหน้าจอและวิเคราะห์สถานะหน้าจอได้
UI Automator ไม่มีการซิงโครไนซ์อัตโนมัติ ดังนั้นการทดสอบจึงไวต่อจังหวะเวลา หากแอนิเมชันยังไม่เสร็จสมบูรณ์หรือ View ยังไม่ได้เรนเดอร์ findObject อาจไม่พบองค์ประกอบ วิธีแก้ไขคือใช้ UiDevice.wait() โดยมีการกำหนดเวลาที่เพียงพอ
สรุป
ชุดเครื่องมือ UI Automator ครอบคลุมสถานการณ์การทดสอบข้ามแอปพลิเคชันที่สำคัญทั้งหมดและเป็นมาตรฐานสำหรับระบบอัตโนมัติของ Android ในระดับระบบ
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม