Android – эспрессо – нажатие на запись listview на основе пользовательских объектов

Espresso используется для автоматического тестирования моего приложения.

Изменить: ниже вы найдете несколько ответов!

Как я могу щелкнуть (в автоматическом сценарии сценария Espresso) на записи в длинном списке пользовательских объектов?

В документации Espresso есть пример LongList. Работа со списком объектов – это то, что я обычно делаю. Попытка множества вариантов перехода от карты к объекту пока не дала хороших результатов.

В документации Espresso говорится, что необходимо использовать 'onData'. Итак, что-то вроде:

onData( myObjectHasContent("my_item: 50")).perform(click()); onView(withId( R.id.selection_pos2)).check(matches(withText("50"))); 

Мои вопросы (и я думаю, что они полезны для обучающегося сообщества): – Можете ли вы написать для этого хорошего Матчи? – Как мы можем использовать это в 'onData'?

Что за ситуация? На экране у меня есть список объектов, таких как:

 public class MyOjbect { public String content; public int size; } 

Адаптер, который я использую для заполнения заполненного списка:

 public class MyObjectWithItemAndSizeAdapter extends ArrayAdapter<MyObjectWithItemAndSize> { private final Context context; private final List<MyObjectWithItemAndSize> values; ... @Override public View getView(int position, View concertView, ViewGroup parent) { View view = null; if (concertView != null) { view = (LinearLayout) concertView; } else { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate( R.layout.list_item, parent, false); } TextView itemT = (TextView) view.findViewById( R.id.item_content); itemT.setText( values.get(position).item); TextView sizeT = (TextView) view.findViewById( R.id.item_size); sizeT.setText( "" + values.get(position).size); return view; } } 

Solutions Collecting From Web of "Android – эспрессо – нажатие на запись listview на основе пользовательских объектов"

Соединитель, присвоенный onData() должен соответствовать желаемому значению, возвращаемому Adapter.getItem(int) желаемого ListView .

Итак, в вашем примере совпадение должно быть примерно таким:

 public static Matcher<Object> withContent(final String content) { return new BoundedMatcher<Object, MyObjectWithItemAndSize>(MyObjectWithItemAndSize.class) { @Override public boolean matchesSafely(MyObjectWithItemAndSize myObj) { return myObj.content.equals(content); } @Override public void describeTo(Description description) { description.appendText("with content '" + content + "'"); } }; } 

В дополнение к предыдущему ответу, я создаю полную версию с двумя типами валидаций. Это может помочь вам понять Espresso и Custom Matchers.

Разница со стандартным примером Espresso LongList заключается в том, что я использую список пользовательских объектов для отображения в списке. Прокрутка по списку справа и проверка результата показана ниже.

Метод 1 – проверка на строку

В тестовом скрипте:

 onData( allOf( instanceOf( MyObjectWithItemAndSize.class), myCustomObjectShouldHaveString( "my_item: 60"))) .perform(click()); // testing the result ... as in the longlist example onView(withId(R.id.selection_pos2)).check(matches(withText("my_item: 60"))); 

Соединитель:

 public static Matcher<Object> myCustomObjectShouldHaveString( String expectedTest) { return myCustomObjectShouldHaveString( equalTo( expectedTest)); } private static Matcher<Object> myCustomObjectShouldHaveString(final Matcher<String> expectedObject) { return new BoundedMatcher<Object, MyObjectWithItemAndSize>( MyObjectWithItemAndSize.class) { @Override public boolean matchesSafely(final MyObjectWithItemAndSize actualObject) { // next line is important ... requiring a String having an "equals" method if( expectedObject.matches( actualObject.item) ) { return true; } else { return false; } } @Override public void describeTo(final Description description) { // could be improved, of course description.appendText("getnumber should return "); } }; } 

Способ 2: проверка на (полный объект).

В тестовом скрипте вы найдете:

 MyObjectWithItemAndSize myObject = new MyObjectWithItemAndSize( "my_item: 60", 11); onData( allOf( instanceOf( MyObjectWithItemAndSize.class), myObjectHasContent( myObject))).perform( click()); onView(withId( R.id.selection_pos2)).check(matches(withText("my_item: 60"))); 

Соединитель.

Самая важная строка (с которой я боролся) ниже // ****

 public static Matcher<Object> myObjectHasContent( MyObjectWithItemAndSize expectedObject) { return myObjectHasContent( equalTo( expectedObject)); } //private method that does the work of matching private static Matcher<Object> myObjectHasContent(final Matcher<MyObjectWithItemAndSize> expectedObject) { return new BoundedMatcher<Object, MyObjectWithItemAndSize>(MyObjectWithItemAndSize.class) { @Override public boolean matchesSafely( final MyObjectWithItemAndSize actualObject) { // ****** ... the 'matches'. See below. // this requires the MyObjectWithItemAndSize to have an 'equals' method if( expectedObject.matches( actualObject) ) { return true; } else { return false; } } @Override public void describeTo(final Description description) { description.appendText("getnumber should return "); } }; } 

Очень важно, что пользовательский объект имеет этот метод (и, я думаю, переопределяет):

 @Override public boolean equals( Object mob2) { return( (this.item.equals( ((MyObjectWithItemAndSize) mob2).item))); // of course, could have also a check on this.size. } 

И это работает !!!! Pfff, потребовалось некоторое время, но победил. Спасибо также Яшу Ф.

Мне нужно было протестировать и AdapterView с помощью пользовательского адаптера, используя Espresso 2 сегодня. Я закончил использование FeatureMatcher:

 private static FeatureMatcher<Product, String> withProductName(final String productName) { return new FeatureMatcher<Product, String>(equalTo(productName), "with productName", "productName") { @Override protected String featureValueOf(Product actual) { return actual.name; } }; } 

И затем вызывая этот метод утилиты из теста, например:

 onData(withProductName("My Awesome Product")) .inAdapterView(withId(R.id.product_list)) .onChildView(withId(R.id.product_title)) .check(matches(withText("My Awesome Product"))); 

Я думаю, что FeatureMatcher отлично работает, когда вы хотите утверждать конкретное свойство объекта данных.