Espresso, iki tür liste için belirli bir öğeye gitme veya öğe üzerinde işlem yapma mekanizmaları sunar: adaptör görünümleri ve geri dönüşümcü görünümleri.
Listelerle çalışırken, özellikle bir RecyclerView
veya AdapterView
nesnesiyle oluşturulan listelerde, ilgilendiğiniz görünüm ekranda bile görünmeyebilir. Bunun nedeni, çok az sayıda alt öğenin görüntülenmesi ve siz sayfayı kaydırdıkça geri dönüştürülmesidir. Mevcut bir görünüm gerektirdiği için scrollTo()
yöntemi bu durumda kullanılamaz.
Bağdaştırıcı görünümü liste öğeleriyle etkileşim kurma
onView()
yöntemini kullanmak yerine, aramanızı onData()
ile başlatın ve eşleştirmek istediğiniz görünümü destekleyen veriler için bir eşleştirici sağlayın.
Espresso, Adapter
nesnesindeki satırı bulma ve öğeyi görüntü alanında görünür hale getirme işlemlerinin tamamını yapar.
Verileri özel bir görünüm eşleştirici kullanarak eşleştirme
Aşağıdaki etkinlik, Map<String, Object>
nesnesindeki her satıra ait verileri barındıran bir SimpleAdapter
tarafından desteklenen bir ListView
içerir.
Her eşlemede iki giriş vardır: "item: x"
gibi Dize içeren bir anahtar "STR"
ve içeriğin uzunluğunu temsil eden Integer
içeren bir "LEN"
anahtarı. Örneğin:
{"STR" : "item: 0", "LEN": 7}
"item: 50" içeren satırdaki bir tıklamaya ilişkin kod aşağıdaki gibi görünür:
Kotlin
onData(allOf(`is`(instanceOf(Map::class.java)), hasEntry(equalTo("STR"), `is`("item: 50")))).perform(click())
Java
onData(allOf(is(instanceOf(Map.class)), hasEntry(equalTo("STR"), is("item: 50")))) .perform(click());
Espresso'nun gerektiğinde listede otomatik olarak kaydırdığını unutmayın.
onData()
içindeki Matcher<Object>
parçalarını inceleyelim. is(instanceOf(Map.class))
yöntemi, aramayı bir Map
nesnesi tarafından desteklenen AdapterView
içindeki herhangi bir öğeyle daraltır.
Örneğimizde, sorgunun bu özelliği liste görünümünün her satırıyla eşleşir, ancak özellikle bir öğeyi tıklamak istediğimizden aramayı aşağıdaki şekilde daraltırız:
Kotlin
hasEntry(equalTo("STR"), `is`("item: 50"))
Java
hasEntry(equalTo("STR"), is("item: 50"))
Bu Matcher<String, Object>
, "STR"
anahtarı ve "item: 50"
değerine sahip bir giriş içeren tüm eşlemelerle eşleşir. Bunu aramak için kullanılacak kod uzun olduğundan ve bunu başka konumlarda tekrar kullanmak istediğimizden, bunun için özel bir withItemContent
eşleştirici yazalım:
Kotlin
return object : BoundedMatcher<Object, Map>(Map::class.java) { override fun matchesSafely(map: Map): Boolean { return hasEntry(equalTo("STR"), itemTextMatcher).matches(map) } override fun describeTo(description: Description) { description.appendText("with item content: ") itemTextMatcher.describeTo(description) } }
Java
return new BoundedMatcher<Object, Map>(Map.class) { @Override public boolean matchesSafely(Map map) { return hasEntry(equalTo("STR"), itemTextMatcher).matches(map); } @Override public void describeTo(Description description) { description.appendText("with item content: "); itemTextMatcher.describeTo(description); } };
Yalnızca Map
türündeki nesneleri eşleştireceğiniz için temel olarak BoundedMatcher
kullanırsınız. Eşleştiriciyi daha önce ekleyerek matchesSafely()
yöntemini geçersiz kılın ve bağımsız değişken olarak iletebileceğiniz bir Matcher<String>
ile eşleştirin. Bu, withItemContent(equalTo("foo"))
numarasını aramanıza olanak tanır. Kodun kısaltması için equalTo()
öğesini zaten çağıran ve String
nesnesini kabul eden başka bir eşleştirici oluşturabilirsiniz:
Kotlin
fun withItemContent(expectedText: String): Matcher<Object> { checkNotNull(expectedText) return withItemContent(equalTo(expectedText)) }
Java
public static Matcher<Object> withItemContent(String expectedText) { checkNotNull(expectedText); return withItemContent(equalTo(expectedText)); }
Artık öğeyi tıklama kodu basittir:
Kotlin
onData(withItemContent("item: 50")).perform(click())
Java
onData(withItemContent("item: 50")).perform(click());
Bu testin tam kodu için AdapterViewTest
sınıfındaki testClickOnItem50()
yöntemine ve GitHub'daki bu özel LongListMatchers
eşleyiciye göz atın.
Belirli bir alt görünümle eşleştirme
Yukarıdaki örnek, tüm ListView
satırının ortasına bir tıklama gönderir.
Ancak, satırın belirli bir alt öğesi üzerinde çalışmak istersek ne olur? Örneğin, ilk sütundaki içeriğin String.length değerini görüntüleyen LongListActivity
satırının ikinci sütununu tıklamak isteriz:
DataInteraction
uygulamanıza bir onChildView()
spesifikasyonu eklemeniz yeterlidir:
Kotlin
onData(withItemContent("item: 60")) .onChildView(withId(R.id.item_size)) .perform(click())
Java
onData(withItemContent("item: 60")) .onChildView(withId(R.id.item_size)) .perform(click());
Geri dönüşüm görünümü listesindeki öğelerle etkileşime geçme
RecyclerView
nesneleri AdapterView
nesnelerinden farklı çalışır, bu nedenle onData()
bunlarla etkileşim kurmak için kullanılamaz.
Espresso kullanarak RecyclerViews ile etkileşimde bulunmak için espresso-contrib
paketini kullanabilirsiniz. Bu pakette, konumlara ilerlemek veya öğeler üzerinde işlem gerçekleştirmek için kullanılabilen bir
RecyclerViewActions
koleksiyonu bulunur:
scrollTo()
- Varsa eşleşen görünüme gider.scrollToHolder()
: Varsa eşleşen Görüntüleme Sahibi'ne gider.scrollToPosition()
: Belirli bir konuma gider.actionOnHolderItem()
- Eşleşen bir Görüntüleme Sahibi üzerinde Görüntüleme İşlemi gerçekleştirir.actionOnItem()
- Eşleşen bir Görünümde Görüntüleme İşlemi gerçekleştirir.actionOnItemAtPosition()
- Belirli bir konumdaki bir görünümde bir ViewAction gerçekleştirir.
Aşağıdaki snippet'lerde RecyclerViewSample örneğinden bazı örnekler yer almaktadır:
Kotlin
@Test(expected = PerformException::class) fun itemWithText_doesNotExist() { // Attempt to scroll to an item that contains the special text. onView(ViewMatchers.withId(R.id.recyclerView)) .perform( // scrollTo will fail the test if no item matches. RecyclerViewActions.scrollTo( hasDescendant(withText("not in the list")) ) ) }
Java
@Test(expected = PerformException.class) public void itemWithText_doesNotExist() { // Attempt to scroll to an item that contains the special text. onView(ViewMatchers.withId(R.id.recyclerView)) // scrollTo will fail the test if no item matches. .perform(RecyclerViewActions.scrollTo( hasDescendant(withText("not in the list")) )); }
Kotlin
@Test fun scrollToItemBelowFold_checkItsText() { // First, scroll to the position that needs to be matched and click on it. onView(ViewMatchers.withId(R.id.recyclerView)) .perform( RecyclerViewActions.actionOnItemAtPosition( ITEM_BELOW_THE_FOLD, click() ) ) // Match the text in an item below the fold and check that it's displayed. val itemElementText = "${activityRule.activity.resources .getString(R.string.item_element_text)} ${ITEM_BELOW_THE_FOLD.toString()}" onView(withText(itemElementText)).check(matches(isDisplayed())) }
Java
@Test public void scrollToItemBelowFold_checkItsText() { // First, scroll to the position that needs to be matched and click on it. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.actionOnItemAtPosition(ITEM_BELOW_THE_FOLD, click())); // Match the text in an item below the fold and check that it's displayed. String itemElementText = activityRule.getActivity().getResources() .getString(R.string.item_element_text) + String.valueOf(ITEM_BELOW_THE_FOLD); onView(withText(itemElementText)).check(matches(isDisplayed())); }
Kotlin
@Test fun itemInMiddleOfList_hasSpecialText() { // First, scroll to the view holder using the isInTheMiddle() matcher. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle())) // Check that the item has the special text. val middleElementText = activityRule.activity.resources .getString(R.string.middle) onView(withText(middleElementText)).check(matches(isDisplayed())) }
Java
@Test public void itemInMiddleOfList_hasSpecialText() { // First, scroll to the view holder using the isInTheMiddle() matcher. onView(ViewMatchers.withId(R.id.recyclerView)) .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle())); // Check that the item has the special text. String middleElementText = activityRule.getActivity().getResources() .getString(R.string.middle); onView(withText(middleElementText)).check(matches(isDisplayed())); }
Ek kaynaklar
Android testlerinde Espresso listelerini kullanma hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın.
Sana Özel
- DataAdapterSample:
Listeler ve
AdapterView
nesneleri için Espresso'nunonData()
giriş noktasını gösterir.