web-dev-qa-db-ja.com

Espressoで、AmbiguousViewMatcherExceptionを回避するために同じIDを持つビューを選択する方法

いくつかの画像を持つgridViewを持っています。 gridViewのセルは、同じidとdescを持つ同じ事前定義されたレイアウトから出てきます。

R.id.item_image == 2131493330

onView(withId(is(R.id.item_image))).perform(click());

グリッド内のすべてのセルは同じIDを持っているため、AmbiguousViewMatcherExceptionを取得しました。最初の1つまたはそれらのいずれかを単にピックアップする方法は?ありがとう!

Android.support.test.espresso.AmbiguousViewMatcherException: 'with id:is <2131493330>'は、階層内の複数のビューに一致します。問題のあるビューには、以下の「**** MATCHES ****」のマークが付いています。

+ -------------> ImageView {id = 2131493330、res-name = item_image、desc = Image、visibility = VISIBLE、width = 262、height = 262、has-focus = false、has -focusable = false、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} **** MATCHES ****

+ -------------> ImageView {id = 2131493330、res-name = item_image、desc = Image、visibility = VISIBLE、width = 262、height = 262、has-focus = false、has -focusable = false、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} **** MATCHES **** |

40
lannyf

GridViewを操作するには、onData()を使用する必要があります。

onData(withId(R.id.item_image))
        .inAdapterView(withId(R.id.grid_adapter_id))
        .atPosition(0)
        .perform(click());

このコードは、GridViewの最初のアイテム内の画像をクリックします。

22
denys

マッチャー(withText、withId)と共にインデックスを提供するだけでは解決策が見つからないことに驚きました。受け入れられた答えは、onDataとListViewsを扱っている場合にのみ問題を解決します。

同じresId/text/contentDescを持つ画面に複数のビューがある場合、このカスタムマッチャーを使用して、AmbiguousViewMatcherExceptionを発生させることなく、必要なビューを選択できます。

public static Matcher<View> withIndex(final Matcher<View> matcher, final int index) {
    return new TypeSafeMatcher<View>() {
        int currentIndex = 0;

        @Override
        public void describeTo(Description description) {
            description.appendText("with index: ");
            description.appendValue(index);
            matcher.describeTo(description);
        }

        @Override
        public boolean matchesSafely(View view) {
            return matcher.matches(view) && currentIndex++ == index;
        }
    };
}

例えば:

onView(withIndex(withId(R.id.my_view), 2)).perform(click());

r.id.my_viewの3番目のインスタンスでクリックアクションを実行します。

77
FrostRocket

グリッドビューの状況に完全に関連するわけではありませんが、hamcrest allOfマッチャーを使用して複数の条件を組み合わせることができます。

import static org.hamcrest.CoreMatchers.allOf;

onView(allOf(withId(R.id.login_password), 
             withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
        .check(matches(isCompletelyDisplayed()))
        .check(matches(withHint(R.string.password_placeholder)));
20

最初に見つかったビューに一致するViewMatcherを作成しました。たぶんそれは誰かに役立つでしょう。例えば。 onData()onを使用するAdapterViewがない場合。

/**
 * Created by stost on 15.05.14.
 * Matches any view. But only on first match()-call.
 */
public class FirstViewMatcher extends BaseMatcher<View> {


   public static boolean matchedBefore = false;

   public FirstViewMatcher() {
       matchedBefore = false;
   }

   @Override
   public boolean matches(Object o) {
       if (matchedBefore) {
           return false;
       } else {
           matchedBefore = true;
           return true;
       }
   }

   @Override
   public void describeTo(Description description) {
       description.appendText(" is the first view that comes along ");
   }

   @Factory
   public static <T> Matcher<View> firstView() {
       return new FirstViewMatcher();
   }
}

次のように使用します。

 onView(FirstViewMatcher.firstView()).perform(click());
13
StefanTo

@FrostRocketの回答を試してみましたが、最も有望でしたが、いくつかのカスタマイズを追加する必要がありました。

public static Matcher<View> withIndex(final Matcher<View> matcher, final int index) {
    return new TypeSafeMatcher<View>() {
        int currentIndex;
        int viewObjHash;

        @SuppressLint("DefaultLocale") @Override
        public void describeTo(Description description) {
            description.appendText(String.format("with index: %d ", index));
            matcher.describeTo(description);
        }

        @Override
        public boolean matchesSafely(View view) {
            if (matcher.matches(view) && currentIndex++ == index) {
                viewObjHash = view.hashCode();
            }
            return view.hashCode() == viewObjHash;
        }
    };
}
11
fada21

事例:

onView( withId( R.id.songListView ) ).perform( RealmRecyclerViewActions.scrollTo( Matchers.first(Matchers.withTextLabeled( "Love Song"))) );
onView( Matchers.first(withText( "Love Song")) ).perform( click() );

matchers.class内

public static Matcher<View> first(Matcher<View> expected ){

    return new TypeSafeMatcher<View>() {
        private boolean first = false;

        @Override
        protected boolean matchesSafely(View item) {

            if( expected.matches(item) && !first ){
                return first = true;
            }

            return false;
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("Matcher.first( " + expected.toString() + " )" );
        }
    };
}
6
Juan Mendez

また、グリッドビューには特に関連していませんが、他の人に役立つ場合には、(RecyclerViewとmy ルートレイアウトには同じidがあり、bothscreened画面に。私が解決するのを助けたのは、次のようなdescendancyをチェックすることでした:

 onView(allOf(withId(R.id.my_view), not(isDescendantOfA(withId(R.id.recyclerView))))).check(matches(withText("My Text")));

enter image description here

4

NthMatcherは次のように簡単に作成できます。

   class NthMatcher internal constructor(private val id: Int, private val n: Int) : TypeSafeMatcher<View>(View::class.Java) {
        companion object {
            var matchCount: Int = 0
        }
        init {
            var matchCount = 0
        }
        private var resources: Resources? = null
        override fun describeTo(description: Description) {
            var idDescription = Integer.toString(id)
            if (resources != null) {
                try {
                    idDescription = resources!!.getResourceName(id)
                } catch (e: Resources.NotFoundException) {
                    // No big deal, will just use the int value.
                    idDescription = String.format("%s (resource name not found)", id)
                }

            }
            description.appendText("with id: $idDescription")
        }

        public override fun matchesSafely(view: View): Boolean {
            resources = view.resources
            if (id == view.id) {
                matchCount++
                if(matchCount == n) {
                    return true
                }
            }
            return false
        }
    }

次のように宣言します。

fun withNthId(resId: Int, n: Int) = CustomMatchers.NthMatcher(resId, n)

そして、次のように使用します:

onView(withNthId(R.id.textview, 1)).perform(click())
0
John

最新*実行->エスプレッソテストの記録

異なる位置の同じIDビューをクリックして、異なるコードを生成しますので、試してください。

実際にこれらの問題を解決します。

0
Pinak Gauswami