Espresso, Google ekibi tarafından geliştirilen ve AndroidX Test'in bir parçası olan Android uygulamaları için otomatik UI testi framework'üdür. İzole bileşenleri kontrol eden enstrümante testlerin aksine, Espresso gerçek UI ile etkileşime girer: düğmelere tıklar, metin girer ve öğelerin görüntülenmesini kontrol eder. Google Android Developers'a göre Espresso, UI iş parçacığı ile otomatik senkronizasyon sağlayarak manuel Thread.sleep() ihtiyacını ortadan kaldırır.
Önemli Noktalar
Espresso, Android için otomatik UI testleri yazmak üzere bir kütüphanedir, Google AndroidX Test'in bir parçasıdır. Ekranda View öğelerini bulmak, üzerlerinde işlem yapmak (tıklama, giriş, kaydırma) ve durumlarını doğrulamak (görüntüleniyor, metin içeriyor, etkin) için API sağlar.
Espresso'nun temel özelliği, uygulamanın ana iş parçacığı ile otomatik senkronizasyondur. Framework, sonraki kontrolü yürütmeden önce tüm asenkron görevlerin (coroutine, AsyncTask, Handler) tamamlanmasını bekler. Bu, yarış koşullarından kaynaklanan dengesiz testleri ortadan kaldırır ve UI testlerini kararlı ve güvenilir hale getirir — hiçbir test Thread.sleep() veya bekleme döngüsü içermez.
Espresso Üç Bacaklı Köpek prensibini izler — bir test üç adımdan oluşur: öğe bul (ViewMatcher), işlem yap (ViewAction), sonucu doğrula (ViewAssertion). Üç adım da bir çağrı zincirinde yazılır: onView().perform().check(). Bu konsept, testleri öngörülebilir ve okunması kolay hale getirir — her test ne aradığını, ne yaptığını ve neyi doğruladığını açıkça belirtir.
Mimari Espresso üç bileşene dayanır: Espresso (giriş noktası — statik metotlar onView ve onData), ViewMatchers (öğe arama), ViewActions (işlemler) ve ViewAssertions(kontroller). Dahili olarak framework, UI iş parçacığı ile senkronizasyon için Idling Resource kullanır.
En basit test, ID'ye göre bir düğme bulur, tıklar ve “Tamamlandı” metninin göründüğünü kontrol eder. Test perspektifinden tüm işlemler senkronizedir — Espresso, test devam etmeden önce UI iş parçacığının olay işlemeyi tamamladığını garanti eder. Bu, yerleşik bir bekleme mekanizması ile sağlanır: onView, UI boşalana kadar test yürütmesini bloke eder.
@Test
fun buttonClick_showsSuccessText() {
// ID'ye göre düğme bul ve tıkla
onView(withId(R.id.button_submit))
.perform(click())
// “Tamamlandı” metninin görüntülendiğini doğrula
onView(withText("Tamamlandı"))
.check(matches(isDisplayed()))
}
Bir Espresso testi başlatmak için, belirli bir durumda (çalışıyor, duraklatılmış veya yok edilmiş) bir Activity oluşturan ActivityScenario (AndroidX Test) kullanılır. ActivityScenario, saf UI testlerine ek olarak Activity yaşam döngüsünü test etmeye olanak tanır. Örneğin, ekran döndürmede (Activity yeniden oluşturma) verilerin korunduğunu ve yok etmeden sonra geri yüklendiğini doğrulayabilirsiniz.
ViewMatchers, Espresso.onView sınıfından, kaynak ID (R.id), metin, ipucu, üst öğe ve hiyerarşi gibi çeşitli kriterlere göre ekranda Views bulmayı sağlayan bir metot kümesidir. Bir matcher benzersiz sonuç vermezse, matcher'lar allOf() ile birleştirilebilir.
| Matcher | Amaç |
|---|---|
| withId(R.id.name) | Kaynak ID'ye göre arama |
| withText(“metin”) | Görüntülenen metne göre arama |
| withHint(“ipucu”) | EditText'in ipucu özniteliğine göre arama |
| isDisplayed() | Öğenin ekranda görünür olduğunu kontrol eder |
| hasSibling(matcher) | Kardeş öğeye göre arama |
| allOf(m1, m2) | Birden çok matcher'ı birleştirme |
Ekranda birden çok aynı öğe varsa (örneğin, farklı metinlere sahip iki TextView), allOf kullanarak matcher'ları birleştirmek uygundur: onView(allOf(withId(R.id.title), withText(“Merhaba”))). Bu, tek bir öğe seçimini garanti eder. Ters operatör — not() — öğeleri aramadan çıkarır ve hasSibling() bilinen bir öğenin yanındaki öğeyi bulur.
ViewActions, Espresso'nun bulunan View üzerinde gerçekleştirdiği işlemlerdir: click(), typeText(), clearText(), scrollTo(), swipeLeft() ve diğerleri. İşlemler, birden çok işlemi sırayla kabul edebilen perform() metoduna iletilir.
perform() metodu vararg ViewAction kabul ederek bir öğe üzerinde işlem sırası yürütmeye olanak tanır: alanı temizle, yeni metin gir, klavyeyi kapat ve düğmeye tıkla. Tüm işlemler listelendikleri sırayla yürütülür ve Espresso, bir sonraki başlamadan önce önceki işlemin tamamlandığını garanti eder.
// EditText'e metin gir ve düğmeye tıkla
onView(withId(R.id.edit_email))
.perform(
clearText(),
typeText("user@example.com"),
closeSoftKeyboard()
)
onView(withId(R.id.button_login))
.perform(click())
AdapterView (ListView, RecyclerView) içindeki öğeler için onView yerine onData() metodu kullanılır. Views yerine adaptör verileriyle çalışır — model içeriğine göre bir öğe bulur ve sonraki işlemler için ilgili View'ı döndürür. onData, model veri alanlarına göre bir öğeyi bulmak için hamcrest matcher'ları kullanır.
ViewAssertions, bir View'ın belirli bir durumda olduğunu doğrular. Temel metot — matches(matcher) — öğenin verilen matcher ile eşleştiğini kontrol eder. Ek olarak Espresso, doesNotExist() (öğe yok) ve selectedDescendantsMatch() (iç içe öğeleri kontrol) sağlar.
UI testlerinde en sık yapılan kontroller: öğe görüntüleniyor (isDisplayed), öğe belirli metni içeriyor (withText), öğe etkin (isEnabled), öğe seçili değil (isNotChecked). Her kontrol başarısızlık durumunda ayrıntılı bir istisna fırlatır — ekrandaki View hiyerarşisi dahil. Bu, hata ayıklamayı basitleştirir: hata mesajı, kontrol anında ekranda gerçekte hangi öğelerin olduğunu gösterir.
Standart kontroller yetersizse, ViewAssertion arayüzü aracılığıyla özel bir kontrol oluşturulabilir. Özel bir assertion, bir View alır ve durumunu programatik olarak kontrol edebilir — örneğin, metin rengi, dolgu veya standart matcher'lar aracılığıyla gösterilmeyen özel bir bileşenin durumu.
// Kontrol: TextView görüntüleniyor ve metin içeriyor
onView(withId(R.id.text_welcome))
.check(matches(isDisplayed()))
.check(matches(withText("Hoş geldiniz")))
// Kontrol: öğe görüntülenMİYOR
onView(withId(R.id.progress_bar))
.check(doesNotExist())
Idling Resource, Espresso'nun testi asenkron işlemlerle senkronize etme mekanizmasıdır. Varsayılan olarak Espresso, Handler, AsyncTask ve coroutine'leri (coroutinesIdlingResource aracılığıyla) bekler. Uygulama özel iş parçacıkları veya geri çağırma hizmetleri aracılığıyla arka plan işi yapıyorsa, özel bir Idling Resource kaydedilmelidir.
AndroidX Test 1.4.0'dan itibaren Espresso, CoroutinesIdlingResource aracılığıyla coroutine'leri destekler. Test, UI kontrollerini gerçekleştirmeden önce başlatılan tüm coroutine'lerin tamamlanmasını otomatik olarak bekler. Daha karmaşık senaryolar için CountingIdlingResource kullanılır — görev başlangıcında artan ve tamamlandığında azalan bir sayaç.
// OkHttp için IdlingResource kaydet
class OkHttpIdlingResource(
private val client: OkHttpClient
) : IdlingResource {
private var isIdle = true
private var watcher: IdlingResource.ResourceCallback? = null
override fun getName() = "OkHttp"
override fun isIdleNow() = isIdle
override fun registerIdleTransitionCallback(
callback: IdlingResource.ResourceCallback
) {
watcher = callback
}
}
Bağlantı Espresso'yu bir Android projesine eklemek, modül düzeyindeki build.gradle'a bağımlılıklar eklenerek yapılır. Espresso, AndroidX Test'in bir parçasıdır, bu nedenle Espresso çekirdeği, uzantıları ve JUnit entegrasyonu için bağımlılıkları belirtmek yeterlidir. Testler src/androidTest dizinine yerleştirilir ve AndroidJUnitRunner aracılığıyla fiziksel bir cihazda veya emülatörde çalıştırılır.
Minimum bağımlılık seti espresso-core (çekirdek), espresso-contrib (RecyclerView, Drawer, Picker için ek matcher'lar) ve runner (AndroidX test çalıştırıcısı) içerir. Tüm testler, Android Test Orchestrator aracılığıyla bir emülatör veya fiziksel cihazda çalıştırılır.
// build.gradle.kts (androidTest bağımlılıkları)
android {
defaultConfig {
testInstrumentationRunner =
"androidx.test.runner.AndroidJUnitRunner"
}
}
dependencies {
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
androidTestImplementation("androidx.test.espresso:espresso-contrib:3.6.1")
androidTestImplementation("androidx.test:runner:1.6.1")
androidTestImplementation("androidx.test:rules:1.6.1")
}
Espresso testleri, her testi ayrı bir süreçte izole eden ve çalıştırmalar arasında durumu temizleyen Google Android Test Orchestrator aracılığıyla çalıştırılabilir. Bu, önceki testlerden kalan verilerin neden olduğu dengesiz testleri ortadan kaldırır ve CI sunucularında kararlılığı artırır. Paralel yürütme için sharding kullanılır — testlerin birden çok emülatör arasında dağıtılması.
Sıkça Sorulan Sorular
Espresso uygulama süreci içinde çalışır ve UI iş parçacığı ile otomatik senkronizasyon kullanır. UI Automator sistem düzeyinde çalışır, diğer uygulamalarla etkileşime girebilir ancak manuel bekleme yönetimi gerektirir.
Bu bir Google sunumundan bir metafordur: Bir Espresso testi üç sütun üzerinde durur — ViewMatcher (bul), ViewAction(yap) ve ViewAssertion(doğrula). Bunlardan birini kaldırmak, üç bacaklı bir köpek gibi testi dengesiz hale getirir.
RecyclerView için espresso-contrib kütüphanesi ve onView(withId(R.id.recycler)).perform(actionOnItemAtPosition(0, click())) gibi metotlar kullanılır. Alternatif, AdapterView için onData() veya RecyclerView içinde metne göre öğe bulmak için özel ViewAction'dır. Ayrıca, espresso-contrib'den RecyclerViewActions bir öğeye kaydırma ve üzerinde işlem yapma için kullanılabilir.
Dengesiz test, kod değişikliği olmadan bazen başarısız olan, yarış koşulları veya asenkronizasyon nedeniyle oluşan testtir. Espresso bu sorunu Idling Resource kullanarak çözer — kontrolleri gerçekleştirmeden önce tüm arka plan görevlerinin tamamlanmasını bekler.
Espresso'nun kendisi ekran görüntüsü testleri için tasarlanmamıştır, ancak Shot veya Paparazzi gibi kütüphanelerle birleştirilebilir. Espresso UI'yı istenen durumda hazırlar ve karşılaştırma kütüphanesi bir ekran görüntüsü alır ve bir referansla karşılaştırır. Bu yaklaşıma görsel regresyon testi denir ve arayüzde beklenmeyen değişiklikleri bulmaya yardımcı olur.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun