Selección de la vista secundaria en índice mediante Espresso

Con Espresso al usar una vista de widget personalizada con vistas de imagen secundaria, ¿qué tipo de Matcher puedo usar para seleccionar el n-ésimo niño? Ejemplo:

+--------->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} 

  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); } }; } 

Para usarlo

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

Para intentar mejorar un poco la solución de Maragues, he hecho algunos cambios.

La solución es crear un Matcher personalizado <View> que abra otro Matcher <View> para la vista primaria, y toma el índice de la vista secundaria para que coincida.

 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); } }; } 

Explicación detallada

Puede anular el método describeTo para dar una descripción fácil de entender del correlador añadiéndolo al argumento Descripción . También querrá propagar la llamada describeTo al matcher padre para que su descripción también se agregue.

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

A continuación, debe reemplazar matchesSafely que determinará cuándo se ha encontrado una coincidencia en la jerarquía de vista. Cuando se llama con una vista cuyo padre coincide con el matador de padres proporcionado, compruebe que la vista es igual al niño en la posición proporcionada.

Si el padre no tiene un childCount mayor que la posición secundaria, getChildAt devolverá null y hará que la prueba se bloquee. Es mejor evitar el colapso y permitir que la prueba falle para que obtengamos un informe de prueba y un mensaje de error adecuados.

 @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. } 

Si puede obtener la vista de los padres. Puede ser este enlace que define un matcher para obtener el primer hijo de una vista puede darle alguna pista.

  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); } }; } 
  • Cómo obtener informes de cobertura de código de google Firebase para Android Espresso tests
  • Prueba de la barra de progreso en Android con Espresso
  • Cómo rotar la actividad, quiero decir: el cambio de orientación de la pantalla con Espresso?
  • Vista de la raíz compatible con Android Espresso
  • Android gradle duplicar archivo LICENSE.txt de nuevo
  • ¿Cómo haces clic en un menú en NavigationView en Android cuando pruebas con Espresso?
  • Appium vs Espresso para el marco de pruebas automatizado
  • Cómo ejecutar Prueba Travis-CI y Espresso
  • Actividad Actual en Espresso android
  • Espresso - haga clic en el texto en la vista de lista
  • Cómo usar Espresso + JMockit
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.