এসপ্রেসো তালিকা

এস্প্রেসো দুটি ধরণের তালিকার জন্য একটি নির্দিষ্ট আইটেমে স্ক্রোল করার বা কাজ করার পদ্ধতি অফার করে: অ্যাডাপ্টার ভিউ এবং রিসাইক্লার ভিউ।

তালিকাগুলির সাথে কাজ করার সময়, বিশেষ করে যেগুলি একটি RecyclerView বা একটি AdapterView অবজেক্টের সাথে তৈরি করা হয়, আপনি যে ভিউতে আগ্রহী তা স্ক্রিনে নাও থাকতে পারে কারণ আপনি স্ক্রোল করার সাথে সাথে শুধুমাত্র অল্প সংখ্যক শিশু প্রদর্শিত হয় এবং পুনর্ব্যবহৃত হয়। scrollTo() পদ্ধতিটি এই ক্ষেত্রে ব্যবহার করা যাবে না কারণ এটির জন্য একটি বিদ্যমান ভিউ প্রয়োজন।

অ্যাডাপ্টার ভিউ তালিকা আইটেমগুলির সাথে ইন্টারঅ্যাক্ট করুন

onView() পদ্ধতি ব্যবহার করার পরিবর্তে, onData() দিয়ে আপনার অনুসন্ধান শুরু করুন এবং আপনি যে ভিউটি মেলাতে চান সেটিকে সমর্থন করে এমন ডেটার বিপরীতে একটি ম্যাচার প্রদান করুন। Adapter অবজেক্টে সারি খোঁজার এবং ভিউপোর্টে আইটেমটিকে দৃশ্যমান করার সমস্ত কাজ এসপ্রেসো করবে।

একটি কাস্টম ভিউ ম্যাচার ব্যবহার করে ডেটা মেলান

নীচের কার্যকলাপে একটি ListView রয়েছে, যা একটি SimpleAdapter দ্বারা সমর্থিত যা একটি Map<String, Object> অবজেক্টে প্রতিটি সারির জন্য ডেটা রাখে।

বর্তমানে পর্দায় প্রদর্শিত তালিকা কার্যকলাপ 23টি আইটেম সহ একটি তালিকা রয়েছে। প্রতিটি আইটেমের একটি সংখ্যা রয়েছে, একটি স্ট্রিং হিসাবে সংরক্ষিত, একটি ভিন্ন নম্বরে ম্যাপ করা হয়েছে, যা পরিবর্তে একটি অবজেক্ট হিসাবে সংরক্ষণ করা হয়।

প্রতিটি মানচিত্রে দুটি এন্ট্রি রয়েছে: একটি কী "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());

মনে রাখবেন যে এসপ্রেসো প্রয়োজন অনুসারে স্বয়ংক্রিয়ভাবে তালিকার মধ্য দিয়ে স্ক্রোল করে।

চলুন onData() ভিতরে Matcher<Object> আলাদা করা যাক। 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());

এই পরীক্ষার সম্পূর্ণ কোডের জন্য, AdapterViewTest ক্লাসের মধ্যে testClickOnItem50() পদ্ধতি এবং GitHub-এ এই কাস্টম LongListMatchers ম্যাচারটি দেখুন।

একটি নির্দিষ্ট শিশুর দৃষ্টিভঙ্গি মিলান

উপরের নমুনাটি একটি ListView এর পুরো সারির মাঝখানে একটি ক্লিক জারি করে। কিন্তু আমরা যদি সারির একটি নির্দিষ্ট শিশুর উপর অপারেশন করতে চাই? উদাহরণস্বরূপ, আমরা LongListActivity এর সারির দ্বিতীয় কলামে ক্লিক করতে চাই, যা প্রথম কলামে বিষয়বস্তুর String.length প্রদর্শন করে:

এই উদাহরণে, বিষয়বস্তুর একটি নির্দিষ্ট অংশের দৈর্ঘ্য বের করা উপকারী হবে। এই প্রক্রিয়ার মধ্যে একটি সারিতে দ্বিতীয় কলামের মান নির্ধারণ করা জড়িত।

আপনার DataInteraction বাস্তবায়নে শুধু একটি onChildView() স্পেসিফিকেশন যোগ করুন:

কোটলিন

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() তাদের সাথে ইন্টারঅ্যাক্ট করতে ব্যবহার করা যাবে না।

Espresso ব্যবহার করে RecyclerViews-এর সাথে ইন্টারঅ্যাক্ট করতে, আপনি espresso-contrib প্যাকেজটি ব্যবহার করতে পারেন, এতে RecyclerViewActions এর একটি সংগ্রহ রয়েছে যা অবস্থানে স্ক্রোল করতে বা আইটেমগুলিতে ক্রিয়া সম্পাদন করতে ব্যবহার করা যেতে পারে:

  • scrollTo() - মিলিত ভিউতে স্ক্রোল করে, যদি এটি বিদ্যমান থাকে।
  • scrollToHolder() - মিলিত ভিউ হোল্ডারে স্ক্রোল করে, যদি এটি বিদ্যমান থাকে।
  • scrollToPosition() - একটি নির্দিষ্ট অবস্থানে স্ক্রোল করে।
  • actionOnHolderItem() - একটি মিলে যাওয়া ভিউ হোল্ডারে একটি ভিউ অ্যাকশন সম্পাদন করে।
  • actionOnItem() - একটি মিলে যাওয়া ভিউতে একটি ভিউ অ্যাকশন সম্পাদন করে।
  • actionOnItemAtPosition() - একটি নির্দিষ্ট অবস্থানে একটি দৃশ্যের উপর একটি ViewAction সঞ্চালন করে।

নিম্নলিখিত স্নিপেটগুলিতে 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 : তালিকা এবং AdapterView অবজেক্টের জন্য Espresso-এর জন্য onData() এন্ট্রি পয়েন্ট দেখায়।