Espresso 목록

Espresso는 2명의 사용자를 위해 특정 항목으로 스크롤하거나 작업할 수 있는 메커니즘을 제공합니다. 목록 유형: 어댑터 뷰와 recycler 뷰입니다.

목록, 특히 RecyclerView 또는 AdapterView 객체가 있는 경우 사용자가 관심 있는 뷰가 소수의 하위 요소만 표시되고 재활용됩니다. 이 경우에는 scrollTo() 메서드를 사용할 수 없습니다. 기존 뷰가 필요하기 때문입니다

어댑터 뷰 목록 항목과 상호작용

onView() 메서드를 사용하는 대신 onData()로 검색을 시작합니다. 일치시키려는 뷰를 지원하는 데이터에 대한 매처를 제공합니다. Espresso가 Adapter 객체에서 행을 찾는 모든 작업을 실행합니다. 항목이 표시 영역에 표시되도록 합니다.

맞춤 뷰 매처를 사용하여 데이터 일치

아래 활동에는 SimpleAdapter에서 지원하는 ListView가 포함되어 있습니다. - Map<String, Object> 객체의 각 행에 대한 데이터를 보유하는 객체입니다.

현재 화면에 표시된 목록 활동에는
          항목 23개 각 항목에는 숫자가 있으며 이 숫자는 문자열로 저장되어
          대신 객체로 저장됩니다.

각 지도에는 다음과 같은 문자열이 포함된 "STR" 키, 이렇게 두 개의 항목이 있습니다. "item: x", 키를 나타내는 Integer가 포함된 "LEN" 키 지정할 수 있습니다. 예를 들면 다음과 같습니다.

{"STR" : "item: 0", "LEN": 7}

'item: 50'이 있는 행을 클릭하기 위한 코드는 다음과 같습니다.

Kotlin

onData(allOf(`is`(instanceOf(Map::class.java)), hasEntry(equalTo("STR"),
        `is`("item: 50")))).perform(click())

자바

onData(allOf(is(instanceOf(Map.class)), hasEntry(equalTo("STR"), is("item: 50"))))
    .perform(click());

Espresso는 필요에 따라 자동으로 목록을 스크롤합니다.

onData() 내부의 Matcher<Object>를 분해해 보겠습니다. 이 is(instanceOf(Map.class)) 메서드는 검색 범위를 AdapterView: Map 객체로 지원됩니다.

여기서는 쿼리의 이 측면은 목록 뷰의 모든 행과 일치하지만 원하는 항목을 찾기 위해 다음을 사용하여 검색 범위를 더 좁힙니다.

Kotlin

hasEntry(equalTo("STR"), `is`("item: 50"))

자바

hasEntry(equalTo("STR"), is("item: 50"))

Matcher<String, Object>은 키 "STR" 및 값 "item: 50" 이를 조회하는 코드는 다른 위치에서 다시 사용하고 싶다면 커스텀 이를 위한 withItemContent 매처:

Kotlin

return object : BoundedMatcher<Object, Map>(Map::class.java) {
    override fun matchesSafely(map: Map): Boolean {
        return hasEntry(equalTo("STR"), itemTextMatcher).matches(map)
    }

    override fun describeTo(description: Description) {
        description.appendText("with item content: ")
        itemTextMatcher.describeTo(description)
    }
}

자바

return new BoundedMatcher<Object, Map>(Map.class) {
    @Override
    public boolean matchesSafely(Map map) {
        return hasEntry(equalTo("STR"), itemTextMatcher).matches(map);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("with item content: ");
        itemTextMatcher.describeTo(description);
    }
};

유형의 객체만 일치시키기 위해 BoundedMatcher를 기본으로 사용합니다. Map matchesSafely() 메서드를 재정의하여 발견된 매처를 삽입합니다. 로 전달할 수 있는 Matcher<String>과 대조합니다. 인수입니다. 이렇게 하면 withItemContent(equalTo("foo"))를 호출할 수 있습니다. 코드용 간결성을 위해 equalTo()를 이미 호출하는 다른 매처를 만들고 다음과 같이 String 객체를 허용합니다.

Kotlin

fun withItemContent(expectedText: String): Matcher<Object> {
    checkNotNull(expectedText)
    return withItemContent(equalTo(expectedText))
}

자바

public static Matcher<Object> withItemContent(String expectedText) {
    checkNotNull(expectedText);
    return withItemContent(equalTo(expectedText));
}

이제 항목을 클릭하는 코드는 간단합니다.

Kotlin

onData(withItemContent("item: 50")).perform(click())

자바

onData(withItemContent("item: 50")).perform(click());

이 테스트의 전체 코드는 testClickOnItem50() 메서드를 살펴보세요. 범위 AdapterViewTest 클래스 및 이 맞춤 LongListMatchers 를 참조하시기 바랍니다.

특정 하위 뷰 일치

위의 샘플은 ListView의 전체 행 중간에서 클릭을 발생시킵니다. 하지만 행의 특정 하위 요소에 관해 작업하려면 어떻게 해야 하나요? 예를 들어 LongListActivity 행의 두 번째 열을 클릭하려고 합니다. 첫 번째 열에 콘텐츠의 String.length를 표시합니다.

이 예에서는 각 시퀀스의 길이만 추출하는 것이
          확인할 수 있습니다. 이 프로세스에는
          행의 두 번째 열 값입니다.

onChildView() 사양을 DataInteraction:

Kotlin

onData(withItemContent("item: 60"))
    .onChildView(withId(R.id.item_size))
    .perform(click())

자바

onData(withItemContent("item: 60"))
    .onChildView(withId(R.id.item_size))
    .perform(click());

Recycler 뷰 목록 항목과 상호작용

RecyclerView 객체는 AdapterView 객체와 다르게 작동하므로 onData()은(는) 상호작용하는 데 사용할 수 없습니다.

Espresso를 사용하여 RecyclerView와 상호작용하려면 espresso-contrib 패키지 - 다음 항목이 포함됩니다. RecyclerViewActions 위치로 스크롤하거나 항목에 대한 작업을 실행하는 데 사용할 수 있는 는 다음과 같습니다.

  • scrollTo() - 일치하는 뷰가 있는 경우 해당 뷰로 스크롤합니다.
  • scrollToHolder() - 일치하는 뷰 홀더가 있는 경우 해당 뷰 홀더로 스크롤합니다.
  • scrollToPosition() - 특정 위치로 스크롤합니다.
  • actionOnHolderItem() - 일치하는 뷰 홀더에서 ViewAction을 실행합니다.
  • actionOnItem() - 일치하는 뷰에서 ViewAction을 실행합니다.
  • actionOnItemAtPosition() - 특정 위치의 뷰에서 ViewAction을 실행합니다.

다음 스니펫에는 RecyclerView샘플 샘플:

Kotlin

@Test(expected = PerformException::class)
fun itemWithText_doesNotExist() {
    // Attempt to scroll to an item that contains the special text.
    onView(ViewMatchers.withId(R.id.recyclerView))
        .perform(
            // scrollTo will fail the test if no item matches.
            RecyclerViewActions.scrollTo(
                hasDescendant(withText("not in the list"))
            )
        )
}

Java

@Test(expected = PerformException.class)
public void itemWithText_doesNotExist() {
    // Attempt to scroll to an item that contains the special text.
    onView(ViewMatchers.withId(R.id.recyclerView))
            // scrollTo will fail the test if no item matches.
            .perform(RecyclerViewActions.scrollTo(
                    hasDescendant(withText("not in the list"))
            ));
}

Kotlin

@Test fun scrollToItemBelowFold_checkItsText() {
    // First, scroll to the position that needs to be matched and click on it.
    onView(ViewMatchers.withId(R.id.recyclerView))
        .perform(
            RecyclerViewActions.actionOnItemAtPosition(
                ITEM_BELOW_THE_FOLD,
                click()
            )
        )

    // Match the text in an item below the fold and check that it's displayed.
    val itemElementText = "${activityRule.activity.resources
        .getString(R.string.item_element_text)} ${ITEM_BELOW_THE_FOLD.toString()}"
    onView(withText(itemElementText)).check(matches(isDisplayed()))
}

Java

@Test
public void scrollToItemBelowFold_checkItsText() {
    // First, scroll to the position that needs to be matched and click on it.
    onView(ViewMatchers.withId(R.id.recyclerView))
            .perform(RecyclerViewActions.actionOnItemAtPosition(ITEM_BELOW_THE_FOLD,
            click()));

    // Match the text in an item below the fold and check that it's displayed.
    String itemElementText = activityRule.getActivity().getResources()
            .getString(R.string.item_element_text)
            + String.valueOf(ITEM_BELOW_THE_FOLD);
    onView(withText(itemElementText)).check(matches(isDisplayed()));
}

Kotlin

@Test fun itemInMiddleOfList_hasSpecialText() {
    // First, scroll to the view holder using the isInTheMiddle() matcher.
    onView(ViewMatchers.withId(R.id.recyclerView))
        .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle()))

    // Check that the item has the special text.
    val middleElementText = activityRule.activity.resources
            .getString(R.string.middle)
    onView(withText(middleElementText)).check(matches(isDisplayed()))
}

Java

@Test
public void itemInMiddleOfList_hasSpecialText() {
    // First, scroll to the view holder using the isInTheMiddle() matcher.
    onView(ViewMatchers.withId(R.id.recyclerView))
            .perform(RecyclerViewActions.scrollToHolder(isInTheMiddle()));

    // Check that the item has the special text.
    String middleElementText =
            activityRule.getActivity().getResources()
            .getString(R.string.middle);
    onView(withText(middleElementText)).check(matches(isDisplayed()));
}

추가 리소스

Android 테스트에서 Espresso 목록을 사용하는 방법에 관한 자세한 내용은 확인할 수 있습니다

샘플

  • DataAdapterSample: 목록 및 AdapterView에 관한 Espresso의 onData() 진입점을 보여줍니다. 객체입니다.