تقدم قهوة الإسبريسو آليات للانتقال إلى عنصر معيّن أو التفاعل معه أنواع القوائم: طرق عرض المهايئات وطرق عرض أداة إعادة التدوير.
عند التعامل مع القوائم، لا سيما تلك التي تم إنشاؤها باستخدام RecyclerView
أو
AdapterView
، حتى أن العرض الذي تهتم به قد لا يظهر
على الشاشة لأنه لا يتم عرض سوى عدد صغير من الأطفال
وإعادة تدويره أثناء التمرير. لا يمكن استخدام طريقة scrollTo()
في هذه الحالة
لأنه يتطلب عرضًا حاليًا.
التفاعل مع عناصر قائمة عرض المحوّل
بدلاً من استخدام الطريقة onView()
، ابدأ البحث باستخدام onData()
قدم مطابقة للبيانات التي تدعم العرض الذي تريد مطابقته.
سيُجري Espresso كل الأعمال للعثور على الصف في الكائن Adapter
مما يجعل العنصر مرئيًا في إطار العرض.
مطابقة البيانات باستخدام مطابقة طريقة عرض مخصّصة
يتضمّن النشاط أدناه "ListView
"، استنادًا إلى "SimpleAdapter
".
يحتوي على بيانات لكل صف في كائن Map<String, Object>
.
ولكل خريطة إدخالان: مفتاح "STR"
يحتوي على سلسلة، مثل
"item: x"
، والمفتاح "LEN"
الذي يحتوي على Integer
، الذي يمثل
طول المحتوى. مثلاً:
{"STR" : "item: 0", "LEN": 7}
الرمز الخاص بنقرة واحدة على الصف الذي يحتوي على "العنصر: 50" يبدو كما يلي:
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 يتم تمريره عبر القائمة تلقائيًا حسب الحاجة.
لنفكك Matcher<Object>
داخل onData()
. تشير رسالة الأشكال البيانية
تعمل طريقة is(instanceOf(Map.class))
على تضييق نطاق البحث إلى أي عنصر من عناصر
AdapterView
، والمدعوم به من كائن Map
.
في حالتنا، يتطابق هذا الجانب من الاستعلام مع كل صف من صفوف عرض القائمة، ولكننا نريد النقر على أحد العناصر تحديدًا، لذلك نضيق نطاق البحث باستخدام:
Kotlin
hasEntry(equalTo("STR"), `is`("item: 50"))
Java
hasEntry(equalTo("STR"), is("item: 50"))
سيطابق Matcher<String, Object>
هذا أي خريطة تحتوي على إدخال مع
المفتاح "STR"
والقيمة "item: 50"
. نظرًا لأن التعليمات البرمجية للبحث عن هذا
ونريد إعادة استخدامه في مواقع أخرى، لنكتب
مطابق واحد (withItemContent
) لذلك:
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); } };
يتم استخدام BoundedMatcher
كقاعدة لأنه لمطابقة العناصر من النوع فقط.
Map
إلغاء الطريقة matchesSafely()
، ووضع المُطابق الذي تم العثور عليه
السابقة، ومطابقتها مع Matcher<String>
يمكنك تمريره
الوسيطة. يتيح لك ذلك الاتصال بـ withItemContent(equalTo("foo"))
. للرموز البرمجية
الإيجاز، يمكنك إنشاء مطابقة أخرى تستدعي بالفعل equalTo()
تقبل كائن String
:
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)); }
الآن رمز النقر فوق العنصر بسيط:
Kotlin
onData(withItemContent("item: 50")).perform(click())
Java
onData(withItemContent("item: 50")).perform(click());
للحصول على الرمز الكامل لهذا الاختبار، اطّلِع على طريقة testClickOnItem50()
.
داخل نطاق
AdapterViewTest
الفئة
هذا LongListMatchers
المخصّص
تطابقه على جيت هب.
مطابقة طريقة عرض فرعية معيّنة
يصدر النموذج أعلاه نقرة في منتصف الصف بأكمله ListView
.
ولكن ماذا لو أردنا العمل على عنصر ثانوي محدد من الصف؟ على سبيل المثال،
تريد النقر على العمود الثاني من صف LongListActivity
،
الذي يعرض String.length للمحتوى في العمود الأول:
ما عليك سوى إضافة مواصفات onChildView()
إلى عملية تنفيذ
DataInteraction
:
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());
التفاعل مع عناصر قائمة عرض أداة إعادة التدوير
تعمل كائنات RecyclerView
بشكل مختلف عن كائنات AdapterView
، لذلك
لا يمكن استخدام onData()
للتفاعل مع المستخدمين.
للتفاعل مع RecyclerViews باستخدام Espresso، يمكنك استخدام
حزمة espresso-contrib
، التي تضم مجموعة من
RecyclerViewActions
التي يمكن استخدامها للانتقال إلى المواضع أو لتنفيذ إجراءات على العناصر:
scrollTo()
- الانتقال إلى طريقة العرض المطابِقة، إن توفّرتscrollToHolder()
: الانتقال إلى "حامل الملف الشخصي" المطابِق، إن كان متوفّرًاscrollToPosition()
: الانتقال إلى موضع معيّنactionOnHolderItem()
- ينفذ إجراء عرض على صاحب ملف شخصي مطابق.actionOnItem()
- ينفذ إجراء عرض على ملف شخصي مطابق.actionOnItemAtPosition()
- لتنفيذ ViewAction على أحد الملفات الشخصية في موضع معيّن.
تعرض المقتطفات التالية بعض الأمثلة من RecyclerViewSample النموذج:
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())); }
مصادر إضافية
لمزيد من المعلومات حول استخدام قوائم قهوة الإسبريسو في اختبارات Android، يُرجى الرجوع إلى الموارد التالية.
نماذج
- DataAdapterSample:
تعرض نقطة الدخول
onData()
لقهوة الإسبريسو، للقوائم وAdapterView
الأخرى.