如何在Espresso测试中按位置选中Tab Layout的指定标签页
Got it, dealing with a TabLayout that has 114 tabs is definitely a case where text-based selection isn't scalable—random testing would be a nightmare otherwise! Here's a reliable way to target tabs by their position instead:
Step 1: Create a Custom childAtPosition Matcher
Espresso doesn't have a built-in matcher to target a child view by its position in a parent, so we'll make our own. This matcher checks if a view is the Nth child of a parent that matches your specified criteria (like your TabLayout's ID).
Java Implementation:
import android.view.View; import android.view.ViewGroup; import androidx.test.espresso.matcher.ViewMatchers; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; public static Matcher<View> childAtPosition( final Matcher<View> parentMatcher, final int position) { return new TypeSafeMatcher<View>() { @Override public void describeTo(Description description) { description.appendText("Child at position " + position + " in parent "); parentMatcher.describeTo(description); } @Override public boolean matchesSafely(View view) { ViewParent parent = view.getParent(); return parent instanceof ViewGroup && parentMatcher.matches(parent) && ((ViewGroup) parent).getChildAt(position).equals(view); } }; }
Kotlin Implementation:
import android.view.View import android.view.ViewGroup import androidx.test.espresso.matcher.ViewMatchers import org.hamcrest.Description import org.hamcrest.Matcher import org.hamcrest.TypeSafeMatcher fun childAtPosition(parentMatcher: Matcher<View>, position: Int): Matcher<View> { return object : TypeSafeMatcher<View>() { override fun describeTo(description: Description) { description.appendText("Child at position $position in parent ") parentMatcher.describeTo(description) } override fun matchesSafely(view: View): Boolean { val parent = view.parent return parent is ViewGroup && parentMatcher.matches(parent) && parent.getChildAt(position) == view } } }
Step 2: Use the Matcher to Click a Tab by Position
Now you can target any tab using its index (note: positions start at 0—so the first tab is position 0, the 114th tab is position 113).
Example Code (Java):
// Replace R.id.your_tablayout_id with your actual TabLayout ID // This clicks the 10th tab (index 9) Espresso.onView(childAtPosition(ViewMatchers.withId(R.id.your_tablayout_id), 9)) .perform(ViewActions.scrollTo(), ViewActions.click());
Example Code (Kotlin):
// Replace R.id.your_tablayout_id with your actual TabLayout ID // This clicks the 50th tab (index 49) onView(childAtPosition(withId(R.id.your_tablayout_id), 49)) .perform(scrollTo(), click())
Key Notes:
- Scrolling: For tabs that aren't visible on screen (which most of your 114 tabs will be), add the
scrollTo()action beforeclick()—Espresso will handle scrolling the TabLayout to bring the target tab into view. - Position Index: Double-check the index (0-based!) to avoid clicking the wrong tab.
- TabLayout-ViewPager Binding: As long as your TabLayout is properly linked to the ViewPager, clicking the tab will automatically trigger the ViewPager to switch to the corresponding page—no extra code needed for the ViewPager itself.
This approach works consistently even with large numbers of tabs, so you can easily randomize positions for your testing (e.g., generate a random integer between 0 and 113 to pick a tab).
内容的提问来源于stack exchange,提问作者Vinayak B

