使用Android Espresso测试具有多个片段的ViewPager

16

我正在尝试测试使用ViewPager的应用程序。每个页面包含多个片段,但这些片段并不总是可见的。我想检查当前可见页面中片段的可见性。

onView(withId(R.id.container_weather))
    .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));

但问题是浓缩咖啡外观都在所有页面上显示,而不仅仅是当前页面,我会得到以下错误:

android.support.test.espresso.AmbiguousViewMatcherException: 'with id: eu.airpatrol.android:id/container_weather' 匹配层次结构中的多个视图...

4个回答

10

我有同样的问题,但使用条件 isCompletelyDisplayed() 可以解决此问题,因为它只考虑屏幕上的视图。

因此,像这样的代码应该可以解决问题:

onView(allOf(withId(R.id.container_weather), isCompletelyDisplayed()))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));

注意:isDisplayed()在某些情况下也可以使用,但它还会考虑到屏幕外的视图,并且如果ViewPager加载了任何其他具有相同视图ID的页面或片段,则无法正常工作。

6

您的测试失败是因为存在多个具有相同id的元素。您可以使用allOf(...)组合条件。然后使用isDisplayed()检查匹配的视图是否在屏幕上可见。以下示例可以正常工作:

onView(allOf(
    withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE),
    withId(R.id.container_weather)))
    .check(matches(isDisplayed()));

1
谢谢您的回复,我尝试了您的解决方案,但仍然存在同样的问题。我有两个页面,两者都包含此片段,并且由于某种原因,两者在视图层次结构中都具有visibility = VISIBLE。 - Ubaier Bhat
你的R.id.container_weather里面有一些独特的文本或子元素吗?如果是,你可以在allOf()中添加这个检查。 - denys
3
这两者唯一的不同之处在于它们的 y 坐标,因为这两个对象位于不同的页面上。:( - Ubaier Bhat
你找到解决方案了吗?我也陷入同样的问题。在我的情况下,两个片段完全相同,只是它们显示的数据有所不同。 - Dibzmania
使用 allOf() 解决了我的问题(谢谢),但请注意,您很可能希望匹配 isDisplayed()isCompletelyDisplayed() 而不是 withEffectiveVisibility(),因为后者方法基于 Viewvisibility 属性进行匹配,而不是屏幕上是否实际可见。 - Adil Hussain

3

遇到了完全相同的问题。我很幸运,因为我的ViewPager中的视图层次结构可以通过它们的兄弟姐妹轻松地进行识别,所以我能够使用hasSibling匹配器解决这个问题,就像这样:

onView(
    allOf(
        hasSibling(withId(R.id.some_sibling)),
        withId(R.id.field_to_test)
    )
).perform(replaceText("123"));

这并不是一个完美的解决方案,因为它可能稍微脆弱,但在我的情况下,我认为这是一个可以接受的妥协。


0

我曾经遇到过类似的问题,当我重复使用按钮布局时,它会给我一个匹配多个视图在层次结构异常的错误。

所以我采用了一个简单的解决方法,就是创建两个不同的屏幕,并使用不同的文本编写两种不同的方法。

  1. 提现界面:

    public WithdrawScreen clickWithdraw() {
        onView(allOf(withId(R.id.save_button), withText("提现")))
            .perform(click());
        return this; 
    }
    
  2. 存款界面:

    public DepositScreen clickDeposit() {
        onView(allOf(withId(R.id.save_button), withText("存款")))
            .perform(click());
        return this;
    }
    
在我的测试中,我创建了两个屏幕的新实例,并根据屏幕引用调用上述方法,这样测试起来比较容易。
WithdrawScreen withdrawInstance = new WithdrawScreen();
withdrawInstance.clickWithdraw();

DepositScreen depositInstance = new DepositScreen();
depositInstance.clickDeposit();

重点是他们正在使用相同的ID - R.id.save_button 用于按钮,而我根据我们所在的片段的可见性替换按钮的文本。
希望对你有所帮助。

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