доступ к детям в пользовательском расширяемом списке с использованием эспрессо Android

Я пытаюсь получить доступ к детям в моем пользовательском расширяемом списке. Список выглядит так:

Пользовательский расширяемый список

Я могу успешно получить доступ к группам с помощью:

Espresso.onView(allOf(withId(R.id.groupRowTextView1), withText(startsWith("Candida")))).perform(click());

Когда я пытаюсь получить доступ к дочернему EditText, например:

    Espresso.onData(is(instanceOf(CustomExpandableListAdapter.class)))
            .inAdapterView(withId(R.id.aversionsListView))
            .onChildView(allOf(withId(R.id.childEditText), isDisplayed()))
            .atPosition(1)
            .perform(click());

Я получаю эту ошибку:

11-30 16:47:45.733    2479-2492/com.foodaversions.people I/TestRunner﹕ ----- begin exception -----
11-30 16:47:45.733    2479-2492/com.foodaversions.people I/TestRunner﹕ com.google.android.apps.common.testing.ui.espresso.PerformException: Error performing 'load adapter data' on view 'with id: is <2131099682>'.
        at com.google.android.apps.common.testing.ui.espresso.PerformException$Builder.build(PerformException.java:67)
        at com.google.android.apps.common.testing.ui.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:57)
        at com.google.android.apps.common.testing.ui.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:40)
        at com.google.android.apps.common.testing.ui.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:159)
        at com.google.android.apps.common.testing.ui.espresso.ViewInteraction.doPerform(ViewInteraction.java:90)
        at com.google.android.apps.common.testing.ui.espresso.ViewInteraction.perform(ViewInteraction.java:73)
        at com.google.android.apps.common.testing.ui.espresso.DataInteraction.load(DataInteraction.java:135)
        at com.google.android.apps.common.testing.ui.espresso.DataInteraction.perform(DataInteraction.java:112)
        at com.foodaversions.people.ModifyAversionsTest.selectGlutenIntolerance(ModifyAversionsTest.java:49)
        at com.foodaversions.people.ModifyAversionsTest.test(ModifyAversionsTest.java:20)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
        at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
        at android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTestCase2.java:192)
        at junit.framework.TestCase.runBare(TestCase.java:134)
        at junit.framework.TestResult$1.protect(TestResult.java:115)
        at junit.framework.TestResult.runProtected(TestResult.java:133)
        at junit.framework.TestResult.run(TestResult.java:118)
        at junit.framework.TestCase.run(TestCase.java:124)
        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:190)
        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:175)
        at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)
        at com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner.onStart(GoogleInstrumentationTestRunner.java:167)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1584)
 Caused by: java.lang.RuntimeException: No data found matching: is an instance of com.foodaversions.people.adapters.CustomExpandableListAdapter contained values: <[Data: GroupStruct{id=6, name='Alcohol Intolerance', sourceTable=AVERSION_NAME, modifierEnum=EDITABLE, childData=
ChildStruct{id=-1, name='<Add Ingredient>', sourceTable=null, joinTable=null, modifierEnum=ADD_TEXT_VIEW}
}
(class: class com.foodaversions.people.data.ExpandableGroupData$GroupStruct) token: 0, Data: GroupStruct{id=8, name='Candida', sourceTable=AVERSION_NAME, modifierEnum=EDITABLE, childData=
ChildStruct{id=13, name='Sugar', sourceTable=AVERSION, joinTable=null, modifierEnum=DELETE}
ChildStruct{id=-1, name='<Add Ingredient>', sourceTable=null, joinTable=null, modifierEnum=ADD_TEXT_VIEW}
}
(class: class com.foodaversions.people.data.ExpandableGroupData$GroupStruct) token: 1, Data: ChildStruct{id=13, name='Sugar', sourceTable=AVERSION, joinTable=null, modifierEnum=DELETE} (class: class com.foodaversions.people.data.ChildStruct) token: 2, Data: ChildStruct{id=-1, name='<Add Ingredient>', sourceTable=null, joinTable=null, modifierEnum=ADD_TEXT_VIEW} (class: class com.foodaversions.people.data.ChildStruct) token: 3, Data: GroupStruct{id=3, name='Dairy Intolerance', sourceTable=AVERSION_NAME, modifierEnum=EDITABLE, childData=
ChildStruct{id=-1, name='<Add Ingredient>', sourceTable=null, joinTable=null, modifierEnum=ADD_TEXT_VIEW}
}
(class: class com.foodaversions.people.data.ExpandableGroupData$GroupStruct) token: 4, Data: GroupStruct{id=10, name='Egg Allergy', sourceTable=AVERSION_NAME, modifierEnum=EDITABLE, childData=
ChildStruct{id=-1, name='<Add Ingredient>', sourceTable=null, joinTable=null, modifierEnum
11-30 16:47:45.733    2479-2492/com.foodaversions.people I/TestRunner﹕ ----- end exception -----

Расширение группы с помощью onData

У меня были проблемы с тем, чтобы дочерний щелчок работал, мне было проще сначала решить, как расширить список:

    Espresso.onData(allOf(is(instanceOf(ExpandableGroupData.GroupStruct.class)), withGroupName("Candida")))
            .inAdapterView(withId(R.id.aversionsListView))
            .perform(click());

Я подумал, что это может помочь найти решение для нажатия на дочерний вид.


Решение

Спасибо @Anna за направление, которое мне нужно было решить:

    // aversionsListView is the id of the ExpandableListView containing the expandable list
    Espresso.onData(allOf(is(instanceOf(ChildStruct.class)), withChildName("<Add Ingredient>")))
            .inAdapterView(withId(R.id.aversionsListView))
            .check(matches(isDisplayed()))
            .perform(click());

сопоставитель:

public static Matcher<Object> withChildName(String name) {
    checkNotNull(name);
    return withChildName(equalTo(name));
}

public static Matcher<Object> withChildName(final Matcher<String> name) {
    checkNotNull(name);
    // ChildStruct is the Class returned by BaseExpandableListAdapter.getChild()
    return new BoundedMatcher<Object, ChildStruct>(ChildStruct.class){

        @Override
        public boolean matchesSafely (final ChildStruct childStruct){
            return name.matches(childStruct.name);
        }

        @Override
        public void describeTo (Description description){
            name.describeTo(description);
        }
    } ;
}

person Rockvole    schedule 01.12.2014    source источник


Ответы (1)


Существует несколько точек использования представлений адаптера. Если он загружает данные из адаптера, вы не можете использовать простой вид, как если бы Espresso не ждал загрузки данных. Если вы собираетесь использовать

Espresso.onData(is(instanceOf(CustomExpandableListAdapter.class))) .inAdapterView(withId(R.id.aversionsListView))

тогда он вернет AdapterListView. Если вы хотите нажать на второй элемент списка, тогда .atPosition(1) можно использовать. Если R.id.childEditText является типом элемента вашего списка, вы должны сопоставить его с пользовательским сопоставлением. Вы не могли использовать .onChildView(allOf(withId(R.id.childEditText), isDisplayed())).atPosition(1) вместе.

Я предлагаю написать собственный сопоставитель. Ознакомьтесь с этим. Пользовательские сопоставители помогают получить элемент списка с сопоставлением его в начале. Вы можете попробовать написать что-то вроде этого.

onData(allOf(is(instanceOf(<List item class for adapter>.class)), withListItemCheck(check_value))).check(matches(isDisplayed()));

Ваш сопоставитель может быть таким:

  public static Matcher<Object> withListItemCheck(final <Type> check_value) {
    checkNotNull(check_value);
    return new BoundedMatcher<Object, <List_Item_class>>(<List_Item_class>.class) {
        private String m_message = "";

        @Override
        public void describeTo(Description d) {
            d.appendText(m_message);
        }

        @Override
        public boolean matchesSafely(<List_Item_class> listItem) {
            m_message = "Expected " + listItem+ " and got ";
            if (listItem== null) {
                m_message +=  "empty";
                return false;
            }
            return <assertion to check `check_value` is corresponding to `listItem` or not>;
        }
    };
}
person Anna    schedule 02.12.2014