【问题标题】:Espresso match first element found when many are in hierarchy当许多在层次结构中时,Espresso 匹配第一个元素
【发布时间】:2015-09-03 23:48:11
【问题描述】:

我正在尝试编写一个 espresso 函数来匹配 espresso 根据我的函数找到的第一个元素,即使找到多个匹配项也是如此。

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

我正在使用这个功能:

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

这会引发 AmbiguousViewMatcherException。

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

【问题讨论】:

    标签: android testing android-espresso


    【解决方案1】:

    您应该能够使用以下代码创建一个仅匹配第一项的自定义匹配器:

    private <T> Matcher<T> first(final Matcher<T> matcher) {
        return new BaseMatcher<T>() {
            boolean isFirst = true;
    
            @Override
            public boolean matches(final Object item) {
                if (isFirst && matcher.matches(item)) {
                    isFirst = false;
                    return true;
                }
    
                return false;
            }
    
            @Override
            public void describeTo(final Description description) {
                description.appendText("should return first matching item");
            }
        };
    }
    

    【讨论】:

    • 我要匹配第n个元素,(即第二个/第三个等)如何实现?
    • 我建议 description.appendText("first item that matches ") 后跟 matcher.describeTo(description) 在失败时提供更好的消息
    【解决方案2】:

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

        private static Matcher<View> getElementFromMatchAtPosition(final Matcher<View> matcher, final int position) {
        return new BaseMatcher<View>() {
            int counter = 0;
            @Override
            public boolean matches(final Object item) {
                if (matcher.matches(item)) {
                    if(counter == position) {
                        counter++;
                        return true;
                    }
                    counter++;
                }
                return false;
            }
    
            @Override
            public void describeTo(final Description description) {
                description.appendText("Element at hierarchy position "+position);
            }
        };
    }
    

    例子:

    您有许多按钮,其 ID 来自您正在使用的库,您想选择第二个按钮。

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

    【讨论】:

      【解决方案3】:

      据我了解,在您的情况下,在您切换货币后,所有价格都应以加元为单位。因此,只需抓住第一项并验证它也应该可以解决您的问题:

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

      【讨论】:

        【解决方案4】:

        对于任何遇到我刚刚遇到的相同问题的人:如果您使用 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
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-15
          • 2013-01-21
          • 1970-01-01
          • 1970-01-01
          • 2015-06-05
          • 1970-01-01
          相关资源
          最近更新 更多