UI Automator test çerçevesi, kullanıcı uygulamaları ve sistem uygulamalarıyla etkileşim kuran kullanıcı arayüzü testleri oluşturmak için bir dizi API sağlar.
Modern UI Automator testine giriş
UI Automator 2.4, Android için kullanıcı arayüzü testleri yazmayı kolaylaştıran, Kotlin dostu, kolaylaştırılmış bir alana özgü dil (DSL) sunar. Bu yeni API yüzeyi, yükleme tabanlı öğe bulma ve uygulama durumları üzerinde açık kontrol üzerine odaklanır. Daha sürdürülebilir ve güvenilir otomatik testler oluşturmak için kullanın.
UI Automator, bir uygulamayı uygulamanın işlemi dışında test etmenize olanak tanır. Bu, küçültme uygulanmış yayın sürümlerini test etmenize olanak tanır. UI Automator, makro karşılaştırma testleri yazarken de yardımcı olur.
Modern yaklaşımın temel özellikleri şunlardır:
- Daha temiz ve daha açıklayıcı test kodu için özel
uiAutomator
test kapsamı. - Açık yüklemlere sahip kullanıcı arayüzü öğelerini bulmak için
onElement
,onElements
veonElementOrNull
gibi yöntemler. - Koşullu öğeler için yerleşik bekleme mekanizması
onElement*(timeoutMs: Long = 10000)
waitForStable
vewaitForAppToBeVisible
gibi açık uygulama durumu yönetimi.- Çok pencereli test senaryoları için erişilebilirlik penceresi düğümleriyle doğrudan etkileşim.
- Görsel test ve hata ayıklama için yerleşik ekran görüntüsü özellikleri ve
ResultsReporter
.
Projenizi oluşturma
Modern UI Automator API'lerini kullanmaya başlamak için projenizin build.gradle.kts
dosyasını en son bağımlılığı içerecek şekilde güncelleyin:
Kotlin
dependencies {
...
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.4.0-alpha05")
}
Groovy
dependencies {
...
androidTestImplementation "androidx.test.uiautomator:uiautomator:2.4.0-alpha05"
}
Temel API kavramları
Aşağıdaki bölümlerde modern UI Automator API'nin temel kavramları açıklanmaktadır.
uiAutomator test kapsamı
uiAutomator { ... }
bloğundaki tüm yeni UI Automator API'lerine erişin. Bu işlev, test işlemleriniz için kısa ve tür açısından güvenli bir ortam sağlayan bir UiAutomatorTestScope
oluşturur.
uiAutomator {
// All your UI Automator actions go here
startApp("com.example.targetapp")
onElement { textAsString() == "Hello, World!" }.click()
}
Kullanıcı arayüzü öğelerini bulma
Kullanıcı arayüzü öğelerini bulmak için UI Automator API'lerini yüklemlerle kullanın. Bu yüklemler, metin, seçili veya odaklanmış durum ve içerik açıklaması gibi özellikler için koşullar tanımlamanıza olanak tanır.
onElement { predicate }
: Varsayılan zaman aşımı süresi içinde koşulla eşleşen ilk kullanıcı arayüzü öğesini döndürür. İşlev, eşleşen bir öğe bulamazsa istisna oluşturur.// Find a button with the text "Submit" and click it onElement { textAsString() == "Submit" }.click() // Find a UI element by its resource ID onElement { id == "my_button_id" }.click() // Allow a permission request watchFor(PermissionDialog) { clickAllow() }
onElementOrNull { predicate }
:onElement
işlevine benzer ancak işlev, zaman aşımı içinde eşleşen bir öğe bulamazsanull
değerini döndürür. İstisna oluşturmaz. Bu yöntemi isteğe bağlı öğeler için kullanın.val optionalButton = onElementOrNull { textAsString() == "Skip" } optionalButton?.click() // Click only if the button exists
onElements { predicate }
: En az bir kullanıcı arayüzü öğesi verilen yüklemle eşleşene kadar bekler, ardından eşleşen tüm kullanıcı arayüzü öğelerinin listesini döndürür.// Get all items in a list Ui element val listItems = onElements { className == "android.widget.TextView" && isClickable } listItems.forEach { it.click() }
onElement
aramalarını kullanmayla ilgili bazı ipuçları:
İç içe yerleştirilmiş öğeler için
onElement
çağrılarını zincirleme: Üst-alt hiyerarşisini izleyerek diğer öğelerin içindeki öğeleri bulmak içinonElement
çağrılarını zincirleyebilirsiniz.// Find a parent Ui element with ID "first", then its child with ID "second", // then its grandchild with ID "third", and click it. onElement { id == "first" } .onElement { id == "second" } .onElement { id == "third" } .click()
Milisaniyeyi temsil eden bir değer ileterek
onElement*
işlevleri için zaman aşımı belirtin.// Find a Ui element with a zero timeout (instant check) onElement(0) { id == "something" }.click() // Find a Ui element with a custom timeout of 10 seconds onElement(10_000) { textAsString() == "Long loading text" }.click()
Kullanıcı arayüzü öğeleriyle etkileşimde bulunma
Tıklamaları simüle ederek veya düzenlenebilir alanlara metin girerek kullanıcı arayüzü öğeleriyle etkileşimde bulunma.
// Click a Ui element
onElement { textAsString() == "Tap Me" }.click()
// Set text in an editable field
onElement { className == "android.widget.EditText" }.setText("My input text")
// Perform a long click
onElement { contentDescription == "Context Menu" }.longClick()
Uygulama durumlarını ve izleyicileri işleme
Uygulamanızın yaşam döngüsünü yönetin ve testleriniz sırasında görünebilecek beklenmedik kullanıcı arayüzü öğelerini ele alın.
Uygulama yaşam döngüsü yönetimi
API'ler, test edilen uygulamanın durumunu kontrol etmenin yollarını sunar:
// Start a specific app by package name. Used for benchmarking and other
// self-instrumenting tests.
startApp("com.example.targetapp")
// Start a specific activity within the target app
startActivity(SomeActivity::class.java)
// Start an intent
startIntent(myIntent)
// Clear the app's data (resets it to a fresh state)
clearAppData("com.example.targetapp")
Beklenmedik kullanıcı arayüzlerini ele alma
watchFor
API'si, test akışınız sırasında görünebilecek izin iletişim kutuları gibi beklenmedik kullanıcı arayüzü öğeleri için işleyiciler tanımlamanıza olanak tanır. Bu yöntem, dahili izleyici mekanizmasını kullanır ancak daha fazla esneklik sunar.
import androidx.test.uiautomator.PermissionDialog
@Test
fun myTestWithPermissionHandling() = uiAutomator {
startActivity(MainActivity::class.java)
// Register a watcher to click "Allow" if a permission dialog appears
watchFor(PermissionDialog) { clickAllow() }
// Your test steps that might trigger a permission dialog
onElement { textAsString() == "Request Permissions" }.click()
// Example: You can register a different watcher later if needed
clearAppData("com.example.targetapp")
// Now deny permissions
startApp("com.example.targetapp")
watchFor(PermissionDialog) { clickDeny() }
onElement { textAsString() == "Request Permissions" }.click()
}
PermissionDialog
, ScopedWatcher<T>
örneğidir. Burada T
, watchFor
içindeki bloğa kapsam olarak iletilen nesnedir. Bu kalıba göre özel izleyiciler oluşturabilirsiniz.
Uygulamanın görünürlüğünü ve kararlılığını bekleyin
Bazen testlerin, öğelerin görünür veya sabit hale gelmesini beklemesi gerekir. UI Automator, bu konuda yardımcı olacak çeşitli API'ler sunar.
waitForAppToBeVisible("com.example.targetapp")
, belirli paket adına sahip bir kullanıcı arayüzü öğesinin özelleştirilebilir bir zaman aşımı içinde ekranda görünmesini bekler.
// Wait for the app to be visible after launching it
startApp("com.example.targetapp")
waitForAppToBeVisible("com.example.targetapp")
Uygulamanın kullanıcı arayüzüyle etkileşime geçmeden önce kararlı olarak kabul edildiğini doğrulamak için waitForStable()
API'sini kullanın.
// Wait for the entire active window to become stable
activeWindow().waitForStable()
// Wait for a specific Ui element to become stable (e.g., after a loading animation)
onElement { id == "my_loading_indicator" }.waitForStable()
Gelişmiş özellikler
Aşağıdaki özellikler, daha karmaşık test senaryoları için kullanışlıdır.
Birden fazla pencereyle etkileşimde bulunma
UI Automator API'leri, kullanıcı arayüzü öğeleriyle doğrudan etkileşim kurmanıza ve bunları incelemenize olanak tanır. Bu özellik, özellikle pencere içinde pencere (PiP) modu veya bölünmüş ekran düzenleri gibi birden fazla pencere içeren senaryolarda kullanışlıdır.
// Find the first window that is in Picture-in-Picture mode
val pipWindow = windows()
.first { it.isInPictureInPictureMode == true }
// Now you can interact with elements within that specific window
pipWindow.onElement { textAsString() == "Play" }.click()
Ekran görüntüleri ve görsel onaylar
Doğrudan testlerinizde ekranın tamamının, belirli pencerelerin veya tek tek kullanıcı arayüzü öğelerinin ekran görüntülerini alın. Bu, görsel regresyon testi ve hata ayıklama için faydalıdır.
uiautomator {
// Take a screenshot of the entire active window
val fullScreenBitmap: Bitmap = activeWindow().takeScreenshot()
fullScreenBitmap.saveToFile(File("/sdcard/Download/full_screen.png"))
// Take a screenshot of a specific UI element (e.g., a button)
val buttonBitmap: Bitmap = onElement { id == "my_button" }.takeScreenshot()
buttonBitmap.saveToFile(File("/sdcard/Download/my_button_screenshot.png"))
// Example: Take a screenshot of a PiP window
val pipWindowScreenshot = windows()
.first { it.isInPictureInPictureMode == true }
.takeScreenshot()
pipWindowScreenshot.saveToFile(File("/sdcard/Download/pip_screenshot.png"))
}
Bitmap için saveToFile
uzantı işlevi, yakalanan görüntünün belirtilen bir yola kaydedilmesini kolaylaştırır.
Hata ayıklama için ResultsReporter'ı kullanma
ResultsReporter
, ekran görüntüleri gibi test yapılarını doğrudan Android Studio'daki test sonuçlarınızla ilişkilendirmenize yardımcı olarak inceleme ve hata ayıklama işlemlerini kolaylaştırır.
uiAutomator {
startApp("com.example.targetapp")
val reporter = ResultsReporter("MyTestArtifacts") // Name for this set of results
val file = reporter.addNewFile(
filename = "my_screenshot",
title = "Accessible button image" // Title that appears in Android Studio test results
)
// Take a screenshot of an element and save it using the reporter
onElement { textAsString() == "Accessible button" }
.takeScreenshot()
.saveToFile(file)
// Report the artifacts to instrumentation, making them visible in Android Studio
reporter.reportToInstrumentation()
}
Eski UI Automator sürümlerinden taşıma
Eski API yüzeyleriyle yazılmış mevcut UI Automator testleriniz varsa modern yaklaşıma geçmek için aşağıdaki tabloyu referans olarak kullanın:
İşlem türü | Eski UI Automator yöntemi | Yeni UI Automator yöntemi |
---|---|---|
Giriş noktası | UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) |
Test mantığını uiAutomator { ... } kapsamına alın. |
Kullanıcı arayüzü öğelerini bulma | device.findObject(By.res("com.example.app:id/my_button")) |
onElement { id == "my\_button" } |
Kullanıcı arayüzü öğelerini bulma | device.findObject(By.text("Click Me")) |
onElement { textAsString() == "Click Me" } |
Boşta kullanıcı arayüzünü bekleme | device.waitForIdle() |
onElement 'nın yerleşik zaman aşımı mekanizmasını tercih edin, aksi takdirde activeWindow().waitForStable() |
Alt öğeleri bulma | Manuel olarak iç içe yerleştirilmiş findObject aramalar |
onElement().onElement() zincirleme |
İzin isteyen iletişim kutularını yönetme | UiAutomator.registerWatcher() |
watchFor(PermissionDialog) |