在ViewPager中匹配多个视图的Espresso Recylerview

10

如何针对实现了匹配多个视图的RecylerView ID的片段的Viewpager进行定位?

我有一个MainActivity,其中包含一个Viewpager。Viewpager有5个标签页。在这5个标签页中,我使用RecylerViews在每个标签页中加载图像。

RecylerView XML在不同的片段中被重用,所以当使用Espresso访问它时,它会抱怨ID匹配多个视图。

<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

我的RecylerView没有加载任何文本,只加载图像,所以我甚至不能使用withText("Text here")。 我也无法对RecylerViews使用onData()

@RunWith(AndroidJUnit4.class)
@LargeTest
public class ExampleTest {

    @Rule
    public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(
            MainActivity.class);

    Activity activity = mActivityRule.getActivity();

    @Test
    public void ExampleMethod() {

        // perform a swipe
        onView(withId(R.id.viewpager)).perform(swipeLeft());  

       // try to click on one of the recycler view items.
       // this crashes:
       onView(withId(R.id.recycler_view))
           .perform(RecyclerViewActions.actionOnItemAtPosition(2, click()));

    }
}

所以它会崩溃并指出错误

android.support.test.espresso.AmbiguousViewMatcherException: 'with id: com.example.app:id/recycler_view' 匹配到层次结构中的多个视图。问题视图在下面用 '****MATCHES****' 标注了出来。

//列出不同的层次结构

View Hierarchy:

View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=720, height=1280, 
  has-focus=false, has-focusable=true, has-window-focus=true, 
  is-clickable=false, is-enabled=true, is-focused=false, 
  is-focusable=false, is-layout-requested=false, is-selected=false, 
  root-is-layout-requested=false, has-input-connection=false, x=0.0, 
  y=0.0, child-count=1}

//...
3个回答

27

当我使用ViewPager时,遇到了同样的问题。将isDisplayed()ViewMatcher中添加进去解决了这个问题(尽管像Espresso中的其他东西一样,它有时可能会失效)...

onView(allOf(isDisplayed(), withId(R.id.recycler_view)))
    .perform(RecyclerViewActions.actionOnItemAtPosition(2, click()));

2
谢谢,但那没用。错误:recycler_view和显示在屏幕上的用户匹配多个视图。 - Tosin Onikute
isDisplayed() 挽救了我的一天,(我有几个来自 TabLayout 的不同选项卡的 RecycleViews)。 - Shondeslitch

2
我所做的是为每个片段设置不同的内容描述,Espresso支持hasContentDescription()withContentDescription()...

如何为片段实例设置内容描述?我没有看到setter。我认为可以为片段布局的根视图设置内容描述。 - rpattabi

2
我用一个变通的方法解决了这个问题,只有实际可见的项目具有与相应布局中指定的值完全匹配的宽度和高度。所有其他视图页面项都具有默认尺寸。
因此,我创建了一个简单的匹配器:
private val sizeMatcher = object : TypeSafeMatcher<View>(){
    override fun describeTo(description: Description?) {
        description?.appendText("with expected size")
    }
    override fun matchesSafely(item: View?): Boolean {
        return item != null && (item.height > DEFAULT_HEIGHT || item.width > DEFAULT_WIDTH)
    } 
}

默认值可能因视图而异

接下来,我在检查表达式中添加了此匹配器:

fun checkDisplayed(viewId: Int) {
    Espresso.onView(Matchers.allOf(ViewMatchers.withId(viewId), ViewMatchers.isDisplayingAtLeast(80), sizeMatcher)).check(ViewAssertions.matches(ViewMatchers.isDisplayingAtLeast(80)))
}

当视图页面刚刚滑动时,显示阈值非常小(80),以便在Espresso没有等待其将滚动视图滚动到屏幕边缘并完全显示它的情况下通过测试用例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接