web-dev-qa-db-ja.com

Espressoは、多数が階層内にあるときに最初に見つかった要素に一致します

複数の一致するアイテムが見つかった場合でも、エスプレッソが私の関数に従って見つけた最初の要素と一致するようにエスプレッソ関数を記述しようとしています。

例:アイテムの価格を含むセルを含むリストビューがあります。通貨をカナダドルに切り替えて、アイテムの価格がCADであることを確認したい。

私はこの関数を使用しています:

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

これにより、AmbiguousViewMatcherExceptionがスローされます。

この場合、CADを表示するセルの数がいくつあっても問題ありません。表示されていることを確認したいだけです。エスプレッソがパラメーターを満たすオブジェクトに遭遇したらすぐにこのテストに合格する方法はありますか?

25
Bebop_

次のコードを使用して、最初のアイテムのみと一致するカスタムマッチャーを作成できるはずです。

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");
        }
    };
}
31
appmattus

同じ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のボタンがたくさんあるので、2番目のボタンを選択します。

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

私が理解していることから、あなたのシナリオでは、通貨を切り替えた後、すべての価格はCAD=)になるはずです。したがって、最初のアイテムを取得して確認するだけで問題も解決するはずです。

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

私がちょうど同じ問題を抱えている人にとっては、1つのViewActionを実行するために共有されたMatcher @appmattusを使用している場合は問題ありませんが、Perform内に複数のViewActionsがある場合、それはできません:

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

viewAction1が実行されますが、実行前にvewAction2、マッチャーが再度評価され、isFirstは常にfalseを返します。一致するビューがないことを示すエラーが表示されます。

したがって、ここでは複数のViewActionsを使用するバージョンで、最初の1つだけでなく、2番目または3番目(または...)を返す可能性があります。

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
        }
    }
}
0
ThomasV