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샘플 샘플:

KotlinJava
@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"))
           
)
       
)
}
@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"))
           
));
}
KotlinJava
@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()))
}
@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()));
}
KotlinJava
@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()))
}
@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() 진입점을 보여줍니다. 객체입니다.