UI Automator to framework od Google do zautomatyzowanego testowania UI aplikacji Android, który działa na poziomie systemu i może wchodzić w interakcje z elementami interfejsu poza jedną aplikacją. W przeciwieństwie do Espresso, UI Automator nie jest przywiązany do procesu konkretnej aplikacji: może otwierać okna dialogowe systemowe, panel powiadomień i przełączać się między aplikacjami. Według Google Android Developers, UI Automator używa standardowego Accessibility Service do dostępu do drzewa UI urządzenia.
Najważniejsze
UI Automator to framework do funkcjonalnego testowania UI Android, który działa na poziomie systemu operacyjnego. Oferuje API do dostępu do dowolnego elementu na ekranie urządzenia, niezależnie od tego, do której aplikacji należy — w tym pasek stanu systemu, okna dialogowe uprawnień, ekran główny i aplikacje innych firm. To czyni go niezastąpionym do testowania scenariuszy wykraczających poza jedną aplikację.
Architektonicznie UI Automator używa Accessibility Service — tego samego serwisu, który jest używany przez TalkBack, Switch Access i inne narzędzia dostępności. Poprzez ten serwis framework uzyskuje pełne drzewo komponentów UI bieżącego ekranu i pozwala wykonywać na nich akcje: kliknięcie, przesunięcie, wprowadzanie tekstu, długie przytrzymanie.
UI Automator pojawił się po raz pierwszy w Android 4.3 (API 18) i od tego czasu jest częścią Android Testing Support Library jako oficjalne narzędzie Google do międzyaplikacyjnego testowania. W AndroidX Test jest dostępny jako osobny artefakt androidx.test.uiautomator:uiautomator w wersji 2.3.0 (2024), który obsługuje wszystkie wersje Android od API 18.
Zasada działania UI Automator opiera się na skanowaniu drzewa Accessibility bieżącego ekranu. Przy wywołaniu metody findObject(selector) framework przegląda hierarchię View, znajduje pierwszy element spełniający warunki UiSelector i zwraca obiekt UiObject — proxy do interakcji z rzeczywistym View.
Typowy test UI Automator zaczyna się od uzyskania instancji UiDevice, która reprezentuje fizyczne urządzenie. UiDevice udostępnia metody do wyszukiwania elementów, zarządzania naciśnięciami przycisków (Home, Back, Recent), obracania ekranu i robienia zrzutów ekranu. Po znalezieniu elementu przez UiSelector wykonywane są akcje na UiObject.
W poniższym przykładzie test otwiera aplikację Settings, znajduje pozycję „Bateria” po tekście i klika ją. UI Automator nie wymaga uruchamiania Activity — działa z dowolnym ekranem urządzenia, w tym z aplikacjami innych firm.
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
// Otwórz ekran ustawień
device.pressHome()
device.wait(Until.hasObject(UiSelector().text("Ustawienia")), 2000)
// Znajdź pozycję „Bateria” i kliknij
val batteryItem = device.findObject(
UiSelector().text("Bateria")
)
batteryItem.clickAndWait(Until.newWindow(), 3000)
UiDevice — główna klasa do interakcji z urządzeniem. Udostępnia metody do wyszukiwania elementów, symulacji naciśnięć przycisków sprzętowych (Home, Back, Menu, Volume), zarządzania zasilaniem, robienia zrzutów ekranu i oczekiwania na określone stany ekranu. UiDevice jest tworzony raz na test i ponownie używany do wszystkich operacji.
UiSelector — to fluent API do wyszukiwania elementów UI. W przeciwieństwie do ViewMatchers z Espresso, UiSelector nie wymaga kompilacji — warunki wyszukiwania są tworzone przez łańcuch metod: text(), className(), description(), resourceId(), index(). Wiele warunków jest łączonych automatycznie przez logiczne AND.
| Metoda UiSelector | Przeznaczenie |
|---|---|
| text(String) | Wyszukiwanie po dokładnym tekście elementu |
| textContains(String) | Wyszukiwanie po fragmencie tekstu |
| resourceId(String) | Wyszukiwanie po ID zasobu (np. com.example:id/button) |
| className(String) | Wyszukiwanie po nazwie klasy View |
| description(String) | Wyszukiwanie po content-description |
| childSelector(selector) | Wyszukiwanie elementu potomnego w kontenerze |
Gdy na ekranie jest kilka elementów z tym samym tekstem, UiSelector pozwala łączyć kryteria: znaleźć kontener po ID, a następnie wewnątrz niego — element po tekście i klasie. To gwarantuje unikalną identyfikację potrzebnego komponentu. Metoda childSelector zawęża obszar wyszukiwania do wskazanego kontenera, co przyspiesza nawigację po drzewie UI.
val scrollView = device.findObject(
UiSelector().resourceId("android:id/list")
)
// Wewnątrz listy znajdź element z tekstem „Wi-Fi”
val wifiItem = scrollView.findObject(
UiSelector().text("Wi-Fi")
wifiItem.click()
Cross-application (międzyaplikacyjne) testowanie — główna funkcja, dla której wybiera się UI Automator. Framework może przełączać się między aplikacjami, testować logowanie OAuth przez przeglądarkę, sprawdzać okna dialogowe systemowe (uprawnienia, wybór aplikacji) oraz wchodzić w interakcje z paskiem stanu systemu, panelem powiadomień i ekranem blokady.
Typowy scenariusz testu cross-app: aplikacja otwiera przeglądarkę do autoryzacji OAuth, użytkownik wprowadza login i hasło, przeglądarka przekierowuje z powrotem do aplikacji. UI Automator przełącza się między procesami, znajduje pola wprowadzania w przeglądarce, wypełnia je i klika „Zaloguj się”.
// Oczekiwanie na pojawienie się przeglądarki
device.wait(Until.hasObject(
UiSelector().packageName("com.android.chrome")
), 5000)
// Znajdź pole wprowadzania email w przeglądarce
val emailField = device.findObject(
UiSelector().className("android.widget.EditText").instance(0)
)
emailField.text = "user@example.com"
UI Automator może sprawdzać i zamykać okna dialogowe systemowe — uprawnienia do geolokalizacji, powiadomienia, dostęp do plików. Jest to kluczowe do testowania pierwszego uruchomienia aplikacji, gdy system kolejno żąda kilku uprawnień. Bez UI Automator takie scenariusze nie mogą być zautomatyzowane, ponieważ okna dialogowe systemowe nie należą do procesu aplikacji.
Wybór między UI Automator a Espresso zależy od scenariusza testowania. Espresso jest zoptymalizowane do testowania jednej aplikacji z automatyczną synchronizacją i minimalnym boilerplate. UI Automator nadaje się do scenariuszy, w których trzeba wchodzić w interakcje z systemem, przeglądarką lub wieloma aplikacjami.
| Kryterium | UI Automator | Espresso |
|---|---|---|
| Zakres | Całe urządzenie, wiele aplikacji | Jedna aplikacja |
| Synchronizacja | Ręczna (wait, sleep) | Automatyczna (Idling Resource) |
| Szybkość | Wolniejszy (dostęp przez serwis) | Szybszy (działa wewnątrz procesu) |
| System UI | Obsługuje (Notifications, Quick Settings) | Nie obsługuje |
| Precyzja wyszukiwania | UiSelector po atrybutach | ViewMatchers po typie i hierarchii |
| Stabilność | Niższa (zależy od czasów) | Wyższa (automatyczne oczekiwanie) |
W praktyce te frameworki są często używane razem: Espresso pokrywa testy UI głównej aplikacji z wysoką stabilnością, a UI Automator jest podłączany do scenariuszy wykraczających poza granice aplikacji — logowanie OAuth, uprawnienia systemowe, praca z Share Intent. Taka kombinacja daje maksymalne pokrycie UI przy minimalnych kosztach utrzymania testów.
Podłączenie UI Automator odbywa się przez dodanie zależności w build.gradle. Framework wchodzi w skład AndroidX Test i nie wymaga dodatkowych uprawnień w manifeście — dostęp do Accessibility Service jest konfigurowany automatycznie przy uruchomieniu testu instrumentalnego.
Minimalna konfiguracja obejmuje artefakt uiautomator i standardowy test runner AndroidJUnitRunner. Testy UI Automator są umieszczane w katalogu src/androidTest i uruchamiane na emulatorze lub fizycznym urządzeniu z 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")
}
Aby uzyskać instancję UiDevice, używa się InstrumentationRegistry.getInstrumentation(). UiDevice należy tworzyć raz w metodzie setUp() i ponownie używać we wszystkich testach klasy, aby oszczędzać zasoby urządzenia. Należy pamiętać, że UiDevice nie jest bezpieczny wątkowo — wszystkie operacje muszą być wykonywane w jednym wątku metody testowej. Tworzenie nowego UiDevice w każdym teście prowadzi do narzutów i spowolnienia wykonania. Zaleca się tworzenie UiDevice raz w metodzie beforeClass i ponowne używanie go we wszystkich testach klasy testowej.
W przeciwieństwie do Espresso, UI Automator nie ma automatycznej synchronizacji. Do oczekiwania na pojawienie się elementów używa się metody UiDevice.wait(condition, timeout) z obiektem Until: Until.findObject(selector), Until.hasObject(selector), Until.gone(selector). Bez prawidłowych oczekiwań testy stają się niestabilne z powodu race condition — element może nie zdążyć pojawić się na ekranie do momentu wyszukiwania. Zaleca się ustawienie czasu oczekiwania na co najmniej 3-5 sekund dla stabilności.
Często zadawane pytania
UI Automator działa na poziomie Accessibility Service i może wchodzić w interakcje z dowolnymi aplikacjami. Espresso działa wewnątrz procesu jednej aplikacji i używa automatycznej synchronizacji z wątkiem UI. UI Automator jest lepszy do scenariuszy międzyaplikacyjnych, Espresso — do stabilnych testów jednej aplikacji.
Tak, UI Automator działa na wszystkich urządzeniach z Android API 18+. Nie wymaga dostępu root — używany jest standardowy Accessibility Service, który jest aktywowany przez Instrumentation przy uruchomieniu testów.
UI Automator używa Accessibility Service do uzyskania pełnego drzewa komponentów UI bieżącego ekranu. Następnie UiSelector przegląda to drzewo i znajduje elementy według zadanych kryteriów: tekst, klasa, ID, content-description lub ich kombinacja.
Tak, metoda UiDevice.takeScreenshot(storePath) pozwala zrobić zrzut bieżącego ekranu i zapisać go do pliku. Jest to przydatne do debugowania: przy upadku testu można zapisać zrzut ekranu i przeanalizować stan ekranu.
UI Automator nie ma automatycznej synchronizacji, dlatego testy są wrażliwe na timing. Jeśli animacja nie została zakończona lub View nie zdążył się wyrenderować, findObject może nie znaleźć elementu. Rozwiązaniem jest użycie UiDevice.wait() z wystarczającym timeoutem.
Podsumowanie
Zestaw narzędzi UI Automator obejmuje wszystkie kluczowe scenariusze testowania międzyaplikacyjnego i jest standardem automatyzacji Android na poziomie systemu.
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również