Το UI Automator είναι ένα πλαίσιο (framework) από την 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 — είναι ένα fluent API για αναζήτηση στοιχείων UI. Σε αντίθεση με τα ViewMatchers στο Espresso, το 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()
Cross-application (δια-εφαρμογική) δοκιμή — η κύρια λειτουργία για την οποία επιλέγεται το UI Automator. Το πλαίσιο μπορεί να εναλλάσσεται μεταξύ εφαρμογών, να δοκιμάζει σύνδεση OAuth μέσω προγράμματος περιήγησης, να ελέγχει διαλόγους συστήματος (άδειες, επιλογή εφαρμογής) και να αλληλεπιδρά με τη γραμμή κατάστασης συστήματος, το πάνελ ειδοποιήσεων και την οθόνη κλειδώματος.
Ένα τυπικό σενάριο δοκιμής cross-app: η εφαρμογή ανοίγει το πρόγραμμα περιήγησης για εξουσιοδότηση OAuth, ο χρήστης εισάγει όνομα χρήστη και κωδικό πρόσβασης, το πρόγραμμα περιήγησης ανακατευθύνει πίσω στην εφαρμογή. Το UI Automator εναλλάσσεται μεταξύ διεργασιών, βρίσκει πεδία εισαγωγής στο πρόγραμμα περιήγησης, τα συμπληρώνει και κάνει κλικ στο “Σύνδεση”.
// Αναμονή εμφάνισης προγράμματος περιήγησης
device.wait(Until.hasObject(
UiSelector().packageName("com.android.chrome")
), 5000)
// Αναζήτηση πεδίου εισαγωγής email στο πρόγραμμα περιήγησης
val emailField = device.findObject(
UiSelector().className("android.widget.EditText").instance(0)
)
emailField.text = "user@example.com"
Το UI Automator μπορεί να ελέγχει και να κλείνει διαλόγους συστήματος — άδειες γεωτοποθεσίας, ειδοποιήσεις, πρόσβαση σε αρχεία. Αυτό είναι κρίσιμο για τη δοκιμή της πρώτης εκκίνησης της εφαρμογής, όταν το σύστημα ζητά διαδοχικά πολλαπλές άδειες. Χωρίς UI Automator, τέτοια σενάρια δεν μπορούν να αυτοματοποιηθούν, επειδή οι διάλογοι συστήματος δεν ανήκουν στη διεργασία της εφαρμογής.
Η επιλογή μεταξύ UI Automator και Espresso εξαρτάται από το σενάριο δοκιμής. Το Espresso είναι βελτιστοποιημένο για δοκιμή μιας εφαρμογής με αυτόματο συγχρονισμό και ελάχιστο boilerplate. Το UI Automator είναι κατάλληλο για σενάρια που απαιτούν αλληλεπίδραση με το σύστημα, το πρόγραμμα περιήγησης ή πολλές εφαρμογές.
| Κριτήριο | UI Automator | Espresso |
|---|---|---|
| Πεδίο | Ολόκληρη συσκευή, πολλές εφαρμογές | Μία εφαρμογή |
| Συγχρονισμός | Χειροκίνητος (wait, sleep) | Αυτόματος (Idling Resource) |
| Ταχύτητα | Πιο αργό (πρόσβαση μέσω υπηρεσίας) | Πιο γρήγορο (λειτουργεί εντός διεργασίας) |
| System UI | Υποστηρίζει (Notifications, Quick Settings) | Δεν υποστηρίζει |
| Ακρίβεια αναζήτησης | 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 δεν είναι thread-safe — όλες οι λειτουργίες πρέπει να εκτελούνται σε ένα νήμα της μεθόδου δοκιμής. Η δημιουργία νέου 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+. Δεν απαιτεί πρόσβαση root — χρησιμοποιείται η τυπική 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. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης