Espresso匹配第一个元素,当许多人在层次结构中时

时间:2015-09-03 23:48:12

标签: android testing android-espresso

我正在尝试根据我的功能编写一个espresso函数来匹配第一个espresso找到的元素,即使找到了多个匹配的项目。

例: 我有一个包含项目价格的单元格的列表视图。我希望能够将货币兑换成加元并验证商品价格是否为加元。

我正在使用此功能:

    onView(anyOf(withId(R.id.product_price), withText(endsWith("CAD"))))
        .check(matches(
                isDisplayed()));

抛出AmbiguousViewMatcherException。

在这种情况下,我不关心有多少或几个单元格显示CAD,我只是想验证它是否显示。有没有办法让espresso在遇到符合参数的物体时立即通过此测试?

4 个答案:

答案 0 :(得分:27)

您应该能够使用以下代码创建仅在第一个项目上匹配的自定义匹配器: 私人< T>匹配< T>第一个(最终匹配< T>匹配器){     返回new BaseMatcher< T>(){         boolean isFirst = true;         @覆盖         public boolean matches(final Object item){             if(isFirst&& matcher.matches(item)){                 isFirst = false;                 返回true;             }             返回false;         }         @覆盖         public void describeTo(final Description description){             description.appendText(“应返回第一个匹配项”);         }     }; }

答案 1 :(得分:7)

我创建了这个匹配器,以防你有许多具有相同特征的元素,例如相同的id,而如果你不仅需要第一个元素,而是想要一个特定的元素。希望这会有所帮助:

  ViewInteraction colorButton = onView(
            allOf(
                    getElementFromMatchAtPosition(allOf(withId(R.id.color)), 2),
                    isDisplayed()));
    colorButton.perform(click());

示例:

您正在使用的库中有许多具有相同ID的按钮,您想要选择第二个按钮。

<?php
    if($_SERVER['REQUEST_URI']=="/index.php")
        header("location:http://www.example.com");
?>

答案 2 :(得分:1)

根据我的理解,在您的方案中,在您切换货币后所有价格都应该是加元。因此,只需抓住第一项并验证它也可以解决您的问题:

onData(anything())
        .atPosition(0)
        .onChildView(allOf(withId(R.id.product_price), withText(endsWith("CAD"))))
        .check(matches(isDisplayed()));

答案 3 :(得分:0)

对于我刚才遇到的同样问题的任何人:如果您使用共享的Matcher @appmattus来执行一个ViewAction,那会很好,但是在执行中有多个ViewAction时,就不会:

onView(first(allOf(matcher1(), matcher2()))
      .perform(viewAction1(), viewAction2())

viewAction1将被执行,但是在执行vewAction2之前,匹配器将被再次求值,并且isFirst将始终返回false。您将收到一条错误消息,指出没有匹配的视图。

因此,这里是一个使用多个ViewAction的版本,如果您愿意,它不仅可以返回第一个,而且还可以返回第二个或第三个(或...):

class CountViewMatcher(val count: Int) : BaseMatcher<View>() {

    private var matchingCount = 0
    private var matchingViewId: Int? = null

    override fun matches(o: Any): Boolean {
        if (o is View) {
            if (matchingViewId != null) {
                // A view already matched the count
                return matchingViewId == o.id
            } else {
                matchingCount++
                if (count == matchingCount) {
                    matchingViewId = o.id
                    return true
                } else {
                    return false
                }
            }
        } else {
            // o is not a view.
            return false
        }
    }
}