いくつかの画像を持つ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 **** |
GridView
を操作するには、onData()
を使用する必要があります。
onData(withId(R.id.item_image))
.inAdapterView(withId(R.id.grid_adapter_id))
.atPosition(0)
.perform(click());
このコードは、GridView
の最初のアイテム内の画像をクリックします。
マッチャー(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番目のインスタンスでクリックアクションを実行します。
グリッドビューの状況に完全に関連するわけではありませんが、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)));
最初に見つかったビューに一致する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());
@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;
}
};
}
事例:
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() + " )" );
}
};
}
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())
最新*実行->エスプレッソテストの記録
異なる位置の同じIDビューをクリックして、異なるコードを生成しますので、試してください。
実際にこれらの問題を解決します。