اسپرسو مکانیسم هایی را برای اسکرول کردن یا عمل کردن روی یک آیتم خاص برای دو نوع لیست ارائه می دهد: نمای آداپتور و نماهای بازیافت.
هنگام سر و کار با لیستها، بهویژه آنهایی که با یک شی RecyclerView
یا AdapterView
ایجاد شدهاند، نمای مورد علاقه شما ممکن است حتی روی صفحه نباشد زیرا فقط تعداد کمی از کودکان نمایش داده میشوند و در حین پیمایش بازیافت میشوند. متد scrollTo()
را نمی توان در این مورد استفاده کرد زیرا به نمای موجود نیاز دارد.
تعامل با آیتم های لیست نمایش آداپتور
به جای استفاده از متد onView()
، جستجوی خود را با onData()
شروع کنید و یک تطبیق در برابر دادههایی که از نمای مورد نظر شما پشتیبانی میکنند، تهیه کنید. اسپرسو تمام کارهای مربوط به یافتن ردیف را در شیء Adapter
و قابل مشاهده کردن آیتم در ویوپورت انجام می دهد.
داده ها را با استفاده از تطبیق نمایش سفارشی مطابقت دهید
فعالیت زیر حاوی ListView
است که توسط SimpleAdapter
پشتیبانی میشود که دادهها را برای هر ردیف در یک Map<String, Object>
نگهداری میکند.
هر نقشه دارای دو ورودی است: یک کلید "STR"
که حاوی یک رشته است، مانند "item: x"
و یک کلید "LEN"
که حاوی یک Integer
است که طول محتوا را نشان می دهد. به عنوان مثال:
{"STR" : "item: 0", "LEN": 7}
کد کلیک بر روی ردیف با "اقلام: 50" به شکل زیر است:
کاتلین
onData(allOf(`is`(instanceOf(Map::class.java)), hasEntry(equalTo("STR"), `is`("item: 50")))).perform(click())
جاوا
onData(allOf(is(instanceOf(Map.class)), hasEntry(equalTo("STR"), is("item: 50")))) .perform(click());
توجه داشته باشید که اسپرسو در صورت نیاز به صورت خودکار در لیست پیمایش می کند.
بیایید Matcher<Object>
در داخل onData()
جدا کنیم. متد is(instanceOf(Map.class))
جستجو را به هر آیتمی از AdapterView
محدود میکند که توسط یک شی Map
پشتیبانی میشود.
در مورد ما، این جنبه از پرس و جو با هر ردیف از نمای فهرست مطابقت دارد، اما ما می خواهیم به طور خاص روی یک مورد کلیک کنیم، بنابراین جستجو را با این موارد محدودتر می کنیم:
کاتلین
hasEntry(equalTo("STR"), `is`("item: 50"))
جاوا
hasEntry(equalTo("STR"), is("item: 50"))
این Matcher<String, Object>
هر نقشه ای را که حاوی ورودی با کلید "STR"
و مقدار "item: 50"
مطابقت می دهد. از آنجا که کد جستجوی این طولانی است و میخواهیم از آن در مکانهای دیگر استفاده کنیم، بیایید یک تطبیق سفارشی withItemContent
برای آن بنویسیم:
کاتلین
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) } }
جاوا
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
را میپذیرد:
کاتلین
fun withItemContent(expectedText: String): Matcher<Object> { checkNotNull(expectedText) return withItemContent(equalTo(expectedText)) }
جاوا
public static Matcher<Object> withItemContent(String expectedText) { checkNotNull(expectedText); return withItemContent(equalTo(expectedText)); }
اکنون کد کلیک بر روی مورد ساده است:
کاتلین
onData(withItemContent("item: 50")).perform(click())
جاوا
onData(withItemContent("item: 50")).perform(click());
برای کد کامل این تست، نگاهی به متد testClickOnItem50()
در کلاس AdapterViewTest
و این تطبیق LongListMatchers
سفارشی در GitHub بیندازید.
با یک نمای کودک خاص مطابقت دهید
نمونه بالا یک کلیک در وسط کل ردیف یک ListView
صادر می کند. اما اگر بخواهیم فرزند خاصی از ردیف را عمل کنیم، چه؟ برای مثال، میخواهیم روی ستون دوم سطر LongListActivity
کلیک کنیم که طول String.length محتوای ستون اول را نشان میدهد:
فقط یک مشخصه onChildView()
را به پیاده سازی DataInteraction
خود اضافه کنید:
کاتلین
onData(withItemContent("item: 60")) .onChildView(withId(R.id.item_size)) .perform(click())
جاوا
onData(withItemContent("item: 60")) .onChildView(withId(R.id.item_size)) .perform(click());
با موارد فهرست نمایش بازیافت کن تعامل داشته باشید
اشیاء RecyclerView
متفاوت از اشیاء AdapterView
کار می کنند، بنابراین onData()
نمی تواند برای تعامل با آنها استفاده شود.
برای تعامل با RecyclerViews با استفاده از Espresso، میتوانید از بسته espresso-contrib
استفاده کنید، که مجموعهای از RecyclerViewActions
دارد که میتواند برای پیمایش به موقعیتها یا انجام اقدامات روی موارد استفاده شود:
-
scrollTo()
- در صورت وجود، به نمای منطبق می رود. -
scrollToHolder()
- در صورت وجود، به نگهدارنده نمایش منطبق می رود. -
scrollToPosition()
- به یک موقعیت خاص پیمایش می کند. -
actionOnHolderItem()
- یک عملکرد View را بر روی یک نگهدارنده نمایش منطبق انجام می دهد. -
actionOnItem()
- یک عملکرد View را روی یک نمای همسان انجام می دهد. -
actionOnItemAtPosition()
- یک ViewAction را روی یک view در یک موقعیت خاص انجام می دهد.
قطعههای زیر نمونههایی از نمونه RecyclerViewSample را نشان میدهند:
کاتلین
@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")) ) ) }
جاوا
@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")) )); }
کاتلین
@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())) }
جاوا
@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())); }
کاتلین
@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())) }
جاوا
@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())); }
منابع اضافی
برای اطلاعات بیشتر در مورد استفاده از لیست اسپرسو در تست های اندروید، به منابع زیر مراجعه کنید.
نمونه ها
- DataAdapterSample : نقطه ورودی
onData()
برای اسپرسو، برای لیست ها و اشیاءAdapterView
نمایش می دهد.