使用Espresso在索引处select子视图

使用Espresso时,使用自定义小部件视图与子图像视图,哪种Matchertypes可以用来select第n个孩子? 例:

+--------->NumberSlider{id=2131296844, res-name=number_slider, visibility=VISIBLE, width=700, height=95, 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=10.0, y=0.0, child-count=7} | +---------->NumberView{id=-1, visibility=VISIBLE, width=99, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, 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} | +---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, 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=99.0, y=0.0} | +---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, 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=199.0, y=0.0} | +---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, 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=299.0, y=0.0} | +---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, 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=399.0, y=0.0} | +---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, 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=499.0, y=0.0} | +---------->NumberView{id=-1, visibility=VISIBLE, width=100, height=95, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=true, 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=599.0, y=0.0} 

Solutions Collecting From Web of "使用Espresso在索引处select子视图"

  public static Matcher<View> nthChildOf(final Matcher<View> parentMatcher, final int childPosition) { return new TypeSafeMatcher<View>() { @Override public void describeTo(Description description) { description.appendText("with "+childPosition+" child view of type parentMatcher"); } @Override public boolean matchesSafely(View view) { if (!(view.getParent() instanceof ViewGroup)) { return parentMatcher.matches(view.getParent()); } ViewGroup group = (ViewGroup) view.getParent(); return parentMatcher.matches(view.getParent()) && group.getChildAt(childPosition).equals(view); } }; } 

使用它

 onView(nthChildOf(withId(R.id.parent_container), 0).check(matches(withText("I am the first child")); 

为了尝试和改进Maragues的解决scheme,我做了一些改变。

解决scheme是创build一个自定义的Matcher <View> ,为父视图封装另一个Matcher <View> ,并使子视图的索引匹配。

 public static Matcher<View> nthChildOf(final Matcher<View> parentMatcher, final int childPosition) { return new TypeSafeMatcher<View>() { @Override public void describeTo(Description description) { description.appendText("position " + childPosition + " of parent "); parentMatcher.describeTo(description); } @Override public boolean matchesSafely(View view) { if (!(view.getParent() instanceof ViewGroup)) return false; ViewGroup parent = (ViewGroup) view.getParent(); return parentMatcher.matches(parent) && parent.getChildCount() > childPosition && parent.getChildAt(childPosition).equals(view); } }; } 

详细说明

您可以重写describeTo方法,以便通过追加到Description参数来简化对匹配器的描述 。 您还需要将describeTo调用传播给父匹配器,所以它的描述也被添加。

 @Override public void describeTo(Description description) { description.appendText("position " + childPosition + " of parent "); // Add this matcher's description. parentMatcher.describeTo(description); // Add the parentMatcher description. } 

接下来,您应该重写matchesSafely ,它将确定何时发现视图层次结构中的匹配。 当使用父母匹配提供的父匹配的视图进行调用时,检查视图是否与提供的位置上的孩子相同。

如果父级没有大于子级的childCountgetChildAt将返回null,并导致testing崩溃。 最好避免崩溃,并让testing失败,以便我们得到正确的testing报告和错误信息。

 @Override public boolean matchesSafely(View view) { if (!(view.getParent() instanceof ViewGroup)) return false; // If it's not a ViewGroup we know it doesn't match. ViewGroup parent = (ViewGroup) view.getParent(); return parentMatcher.matches(parent) // Check that the parent matches. && parent.getChildCount() > childPosition // Make sure there's enough children. && parent.getChildAt(childPosition).equals(view); // Check that this is the right child. } 

如果你能得到父视图。 可能是这个链接定义了一个匹配器来获得一个视图的第一个孩子可以给你一些线索。

  public static Matcher<View> firstChildOf(final Matcher<View> parentMatcher) { return new TypeSafeMatcher<View>() { @Override public void describeTo(Description description) { description.appendText("with first child view of type parentMatcher"); } @Override public boolean matchesSafely(View view) { if (!(view.getParent() instanceof ViewGroup)) { return parentMatcher.matches(view.getParent()); } ViewGroup group = (ViewGroup) view.getParent(); return parentMatcher.matches(view.getParent()) && group.getChildAt(0).equals(view); } }; }