Espresso ile ilgili temel bilgiler

Bu belgede, sık kullanılan otomatik test görevlerinin Espresso API kullanılarak nasıl tamamlanacağı açıklanmaktadır.

Espresso API'si, test yazarlarını bir kullanıcının uygulamayla etkileşimde bulunurken, kullanıcı arayüzü öğelerini bulup onlarla etkileşimde bulunurken neler yapabileceği konusunda düşünmeye teşvik eder. Aynı zamanda çerçeve, etkinliklere ve uygulama görünümlerine doğrudan erişimi engeller, çünkü bu nesnelere bağlı kalmak ve bunları kullanıcı arayüzü iş parçacığı dışında çalıştırmak testteki düşüşün ana kaynaklarından biridir. Bu nedenle, Espresso API'de getView() ve getCurrentActivity() gibi yöntemler görmezsiniz. Kendi ViewAction ve ViewAssertion alt sınıflarınızı uygulayarak görünümler üzerinde güvenle çalışmaya devam edebilirsiniz.

API bileşenleri

Espresso'nun ana bileşenleri şunlardır:

  • Espresso: Görüntülemelerle etkileşimlere giriş noktasıdır (onView() ve onData() üzerinden). Ayrıca herhangi bir görünüme bağlı olması gerekmeyen API'leri de (ör. pressBack()) gösterir.
  • ViewMatchersMatcher<? super View> arayüzünü uygulayan nesne koleksiyonu. Mevcut görünüm hiyerarşisinde bir görünümü bulmak için bunlardan birini veya daha fazlasını onView() yöntemine aktarabilirsiniz.
  • ViewActionsViewInteraction.perform() yöntemine aktarılabilen click() gibi ViewAction nesne koleksiyonu.
  • ViewAssertions: ViewInteraction.check() yöntemi ile iletilebilecek ViewAssertion nesne koleksiyonu. Çoğu zaman, şu anda seçili görünümün durumunu doğrulamak için bir Görünüm eşleştirici kullanan eşleşme onayından yararlanırsınız.

Örnek:

Kotlin

// withId(R.id.my_view) is a ViewMatcher
// click() is a ViewAction
// matches(isDisplayed()) is a ViewAssertion
onView(withId(R.id.my_view))
    .perform(click())
    .check(matches(isDisplayed()))

Java

// withId(R.id.my_view) is a ViewMatcher
// click() is a ViewAction
// matches(isDisplayed()) is a ViewAssertion
onView(withId(R.id.my_view))
    .perform(click())
    .check(matches(isDisplayed()));

Bir görünüm bulun

Durumların büyük çoğunluğunda, onView() yöntemi, mevcut görünüm hiyerarşisinde yalnızca bir görünümle eşleşmesi beklenen bir hamcrest eşleştirici kullanır. Eşleştiriciler güçlüdür ve bunları Mockito veya JUnit ile kullanan kişilere alışıktır. Hamcrest eşleyicilere aşina değilseniz bu sunuya hızlıca göz atmanızı öneririz.

Genellikle, istenen görünüm için benzersiz bir R.id bulunur ve basit bir withId eşleştirici, görünüm aramasını daraltır. Bununla birlikte, test geliştirme zamanında R.id belirleyemediğiniz birçok geçerli durum vardır. Örneğin, belirli bir görünümde R.id bulunmayabilir veya R.id benzersiz değildir. findViewById() ile görünüme erişmenin normal yolu çalışmadığı için bu durum, normal araç testlerinin yazılmasını zorlaştırabilir ve karmaşık hale getirebilir. Dolayısıyla, bu görünümü içeren Etkinlik veya Parça'nın gizli üyelerine erişmeniz ya da bilinen R.id öğesine sahip bir kapsayıcı bulmanız ve belirli görünüm için bu kapsayıcının içeriğine gitmeniz gerekebilir.

Espresso, mevcut ViewMatcher nesnelerini veya kendi özel nesnelerinizi kullanarak görünümü daraltmanıza olanak tanıyarak bu sorunu kolayca çözer.

R.id özelliğine göre bir görünüm bulmak onView() işlevini çağırmak kadar basittir:

Kotlin

onView(withId(R.id.my_view))

Java

onView(withId(R.id.my_view));

Bazen R.id değerleri birden fazla görünüm arasında paylaşılır. Bu durumda belirli bir R.id kullanma girişimi size AmbiguousViewMatcherException gibi bir istisna verir. İstisna mesajı, mevcut görünüm hiyerarşisini metinle temsil eder. Bu temsilde, benzersiz olmayan R.id ile eşleşen görünümleri arayıp bulabilirsiniz:

java.lang.RuntimeException:
androidx.test.espresso.AmbiguousViewMatcherException
This matcher matches multiple views in the hierarchy: (withId: is <123456789>)

...

+----->SomeView{id=123456789, res-name=plus_one_standard_ann_button,
visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true,
window-focus=true, is-focused=false, is-focusable=false, enabled=true,
selected=false, is-layout-requested=false, text=,
root-is-layout-requested=false, x=0.0, y=625.0, child-count=1}
****MATCHES****
|
+------>OtherView{id=123456789, res-name=plus_one_standard_ann_button,
visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true,
window-focus=true, is-focused=false, is-focusable=true, enabled=true,
selected=false, is-layout-requested=false, text=Hello!,
root-is-layout-requested=false, x=0.0, y=0.0, child-count=1}
****MATCHES****

Görünümlerin çeşitli özelliklerini incelediğinizde benzersiz şekilde tanımlanabilir mülkler görebilirsiniz. Yukarıdaki örnekte, görünümlerden birinde "Hello!" metni bulunmaktadır. Kombinasyon eşleştiricileri kullanarak aramanızı daraltmak için bunu kullanabilirsiniz:

Kotlin

onView(allOf(withId(R.id.my_view), withText("Hello!")))

Java

onView(allOf(withId(R.id.my_view), withText("Hello!")));

Ayrıca eşleştiricilerin hiçbirini tersine çevirmemeyi de seçebilirsiniz:

Kotlin

onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))))

Java

onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))));

Espresso tarafından sağlanan görünüm eşleştiriciler için ViewMatchers adresini inceleyin.

Dikkat edilmesi gereken noktalar

  • İyi çalışan bir uygulamada, kullanıcının etkileşimde bulunabileceği tüm görünümler açıklayıcı metin veya bir içerik açıklaması içermelidir. Daha fazla ayrıntı için Uygulamaları daha erişilebilir hale getirme bölümüne bakın. withText() veya withContentDescription() kullanarak bir aramayı daraltamıyorsanız bu durumu bir erişilebilirlik hatası olarak ele alabilirsiniz.
  • Aradığınız görünümü bulan, en az açıklayıcı nitelikteki eşleştiriciyi kullanın. Çerçeveyi gereğinden fazla iş yapmaya zorlayacağından, fazla betimleme yapmayın. Örneğin, bir görünüm metninden benzersiz bir şekilde tanımlanabilirse görünümün de TextView üzerinden atanabilir olduğunu belirtmeniz gerekmez. Çoğu görüntüleme için R.id yeterli olacaktır.
  • Hedef görünüm bir AdapterView içindeyse (ör. ListView, GridView veya Spinner) onView() yöntemi çalışmayabilir. Bu durumlarda bunun yerine onData() kullanmanız gerekir.

Bir görünümde işlem gerçekleştirme

Hedef görünüm için uygun bir eşleştirici bulduğunuzda, gerçekleştirme yöntemini kullanarak bunun üzerinde ViewAction örnekleri gerçekleştirebilirsiniz.

Örneğin, görünümü tıklamak için:

Kotlin

onView(...).perform(click())

Java

onView(...).perform(click());

Tek bir gerçekleştirme çağrısıyla birden fazla işlem yürütebilirsiniz:

Kotlin

onView(...).perform(typeText("Hello"), click())

Java

onView(...).perform(typeText("Hello"), click());

Üzerinde çalıştığınız görünüm bir ScrollView (dikey veya yatay) içinde yer alıyorsa scrollTo() ile görünümün görüntülenmesini gerektiren click() ve typeText() gibi önceki işlemleri değerlendirin. Bu şekilde, diğer işleme geçmeden önce görünümün görüntülenmesi sağlanır:

Kotlin

onView(...).perform(scrollTo(), click())

Java

onView(...).perform(scrollTo(), click());

Espresso'nun sağladığı görüntüleme işlemleri için ViewActions adresine bakın.

Onayları görüntüleme

Onaylar, şu anda seçili olan görünüme check() yöntemi ile uygulanabilir. En çok kullanılan onaylama, matches() onaylamadır. Seçili olan görünümün durumunu doğrulamak için bir ViewMatcher nesnesi kullanır.

Örneğin, bir görünümde "Hello!" metninin olup olmadığını kontrol etmek için:

Kotlin

onView(...).check(matches(withText("Hello!")))

Java

onView(...).check(matches(withText("Hello!")));

"Hello!" içeriğinin görünüm içeriği olduğunu iddia etmek istiyorsanız aşağıdaki durum kötü uygulama olarak kabul edilir:

Kotlin

// Don't use assertions like withText inside onView.
onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()))

Java

// Don't use assertions like withText inside onView.
onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()));

Diğer yandan, "Hello!" metnini içeren bir görünümün görünür olduğunu, örneğin görünümlerin görünürlük işareti değişikliğinden sonra olduğunu iddia etmek istiyorsanız kod kullanılabilir.

Onaylama basit testini görüntüle

Bu örnekte SimpleActivity, bir Button ve bir TextView içeriyor. Düğme tıklandığında TextView içeriği "Hello Espresso!" olarak değişir.

Bunu Espresso ile şu şekilde test edebilirsiniz:

Düğmeyi tıklayın

İlk adım, düğmeyi bulmanıza yardımcı olacak bir özellik aramaktır. SimpleActivity içindeki düğmede beklendiği gibi benzersiz bir R.id var.

Kotlin

onView(withId(R.id.button_simple))

Java

onView(withId(R.id.button_simple));

Şimdi tıklamayı gerçekleştirmek için:

Kotlin

onView(withId(R.id.button_simple)).perform(click())

Java

onView(withId(R.id.button_simple)).perform(click());

TextView metnini doğrulama

Doğrulanacak metni içeren TextView de benzersiz bir R.id öğesine sahip:

Kotlin

onView(withId(R.id.text_simple))

Java

onView(withId(R.id.text_simple));

Şimdi içerik metnini doğrulamak için:

Kotlin

onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")))

Java

onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")));

Bağdaştırıcı görünümlerinde yüklenen verileri kontrol etme

AdapterView, verilerini bir Bağdaştırıcıdan dinamik olarak yükleyen özel bir widget türüdür. En yaygın AdapterView örneği ListView şeklindedir. LinearLayout gibi statik widget'ların aksine, mevcut görünüm hiyerarşisine AdapterView alt öğelerinin yalnızca bir alt kümesi yüklenebilir. Basit bir onView() araması, o anda yüklü olmayan görünümleri bulmaz.

Espresso, söz konusu bağdaştırıcı öğesinin ilk olarak yüklenmesini sağlayan ayrı bir onData() giriş noktası sağlar. Bu giriş noktası, söz konusu bağdaştırıcı öğesini veya alt öğeleri üzerinde çalıştırmadan önce odak noktasına getirir.

Uyarı: AdapterView özel uygulamaları, devralma sözleşmelerini (özellikle de getItem() API'yi) bozarsa onData() yöntemi ile ilgili sorunlara yol açabilir. Bu gibi durumlarda en iyi yaklaşım, uygulama kodunuzu yeniden düzenlemektir. Bunu yapamazsanız eşleşen bir özel AdapterViewProtocol uygulayabilirsiniz. Daha fazla bilgi için Espresso'nun sunduğu varsayılan AdapterViewProtocols sınıfına göz atın.

Bağdaştırıcı görünümü basit testi

Bu basit testte onData() ürününün nasıl kullanılacağı gösterilmektedir. SimpleActivity, kahve içecek türlerini temsil eden birkaç öğeye sahip bir Spinner içeriyor. Bir öğe seçildiğinde "One %s a day!" olarak değişen bir TextView bulunur ve burada %s, seçilen öğeyi temsil eder.

Bu testin amacı Spinner öğesini açmak, belirli bir öğeyi seçmek ve TextView öğesinin bu öğeyi içerdiğini doğrulamaktır. Spinner sınıfı AdapterView temel alınarak belirlendiğinden, öğeyi eşleştirmek için onView() yerine onData() kullanılması önerilir.

Öğe seçimini aç

Kotlin

onView(withId(R.id.spinner_simple)).perform(click())

Java

onView(withId(R.id.spinner_simple)).perform(click());

Öğe seçme

Öğe seçimi için Spinner, içeriğiyle bir ListView oluşturur. Bu görünüm çok uzun olabilir ve öğe, görünüm hiyerarşisine katkıda bulunmayabilir. onData() kullanarak istediğimiz öğeyi görünüm hiyerarşisine dahil ederiz. Spinner içindeki öğeler dize olduğundan "Americano" Dizesine eşit bir öğeyi eşleştirmek istiyoruz:

Kotlin

onData(allOf(`is`(instanceOf(String::class.java)),
        `is`("Americano"))).perform(click())

Java

onData(allOf(is(instanceOf(String.class)), is("Americano"))).perform(click());

Metnin doğru olduğunu onaylayın

Kotlin

onView(withId(R.id.spinnertext_simple))
    .check(matches(withText(containsString("Americano"))))

Java

onView(withId(R.id.spinnertext_simple))
    .check(matches(withText(containsString("Americano"))));

Hata ayıklama

Bir test başarısız olduğunda Espresso yararlı hata ayıklama bilgileri sağlar:

Günlük kaydı

Espresso, tüm görüntüleme işlemlerini logcat'e kaydeder. Örneğin:

ViewInteraction: Performing 'single click' action on view with text: Espresso

Görünüm hiyerarşisi

onView() başarısız olduğunda Espresso, istisna mesajındaki görünüm hiyerarşisini yazdırır.

  • onView() hedef görünümü bulamazsa NoMatchingViewException gönderilir. Eşleyicinin neden hiçbir görünümle eşleşmediğini analiz etmek için istisna dizesindeki görünüm hiyerarşisini inceleyebilirsiniz.
  • onView(), belirtilen eşleştiriciyle eşleşen birden fazla görünüm bulursa AmbiguousViewMatcherException atılır. Görünüm hiyerarşisi yazdırılır ve eşleşen tüm görünümler MATCHES etiketiyle işaretlenir:
java.lang.RuntimeException:
androidx.test.espresso.AmbiguousViewMatcherException
This matcher matches multiple views in the hierarchy: (withId: is <123456789>)

...

+----->SomeView{id=123456789, res-name=plus_one_standard_ann_button,
visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true,
window-focus=true, is-focused=false, is-focusable=false, enabled=true,
selected=false, is-layout-requested=false, text=,
root-is-layout-requested=false, x=0.0, y=625.0, child-count=1}
****MATCHES****
|
+------>OtherView{id=123456789, res-name=plus_one_standard_ann_button,
visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true,
window-focus=true, is-focused=false, is-focusable=true, enabled=true,
selected=false, is-layout-requested=false, text=Hello!,
root-is-layout-requested=false, x=0.0, y=0.0, child-count=1}
****MATCHES****

Karmaşık bir görünüm hiyerarşisi veya widget'ların beklenmedik davranışları üzerinde çalışırken açıklama için Android Studio'daki Hiyerarşi Görüntüleyici'yi kullanmak her zaman faydalı olur.

Bağdaştırıcı görünümü uyarıları

Espresso, kullanıcıları AdapterView widget'larının varlığı konusunda uyarıyor. Bir onView() işlemi NoMatchingViewException gönderdiğinde ve görünüm hiyerarşisinde AdapterView widget'lar olduğunda, en yaygın çözüm onData() kullanmaktır. Özel durum mesajı, bağdaştırıcı görünümlerinin listesini içeren bir uyarı içerir. Bu bilgileri, hedef görünümü yüklemek üzere onData() yöntemini çağırmak için kullanabilirsiniz.

Ek kaynaklar

Android testlerinde Espresso'yu kullanma hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın.

Sana Özel