簡體   English   中英

如何在 Espresso 中單擊 RecyclerView 中的項目

[英]How to click on an item inside a RecyclerView in Espresso

我有一個 RecyclerView (R.id.recyclerView),其中每一行都有一個圖像 (R.id.row_image) 和一個 TextView。 我想單擊第一行中的圖像。
我試過使用 onData(..) 但它似乎不起作用。

使用RecyclerViewActions

onView(withId(R.id.recyclerView))
    .perform(actionOnItemAtPosition(0, click()));

將此包含在您的 gradle 腳本中:

dependencies {
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
    androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.0'
}

只是為了添加 Gabor 的答案(這是自 Espresso 2.0 以來正確且完整的答案)。

您目前在使用espresso-contribRecyclerView時可能會遇到問題(請參閱android-test-kit 票證)。

解決方法是在上面提到的espresso-contrib依賴項 Gabor 中添加此排除項:

androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.0') {
    exclude group: 'com.android.support', module: 'appcompat'
    exclude group: 'com.android.support', module: 'support-v4'
    exclude module: 'recyclerview-v7'
}

(這是一個答案而不是對 Gabor 答案的評論,因為我還沒有發表評論的權利)

編輯:

Espresso 2.0 已經發布,更新日志包括以下內容:

新功能

  • 濃縮咖啡貢獻
    • RecyclerViewActions:處理與 RecyclerViews 的交互

舊答案

我自己還沒有測試過這個,但是 Thomas Keller 在 G+ 上發布了這個,並附有一個簡短的解釋和一個指向帶有必要視圖匹配器的 Gist 的鏈接。

由於新的RecyclerView API 繼承自ViewGroup而不是AdapterView ,因此您不能使用 Espresso 的onData()來測試使用此組件的布局。

鏈接到要點

我會附上代碼,只是為了完整起見(注意:不是我的!所有功勞都歸功於 Thomas Keller)

視圖匹配器:

public class ViewMatchers {
    @SuppressWarnings("unchecked")
    public static Matcher<View> withRecyclerView(@IdRes int viewId) {
        return allOf(isAssignableFrom(RecyclerView.class), withId(viewId));
    }

    @SuppressWarnings("unchecked")
    public static ViewInteraction onRecyclerItemView(@IdRes int identifyingView, Matcher<View> identifyingMatcher, Matcher<View> childMatcher) {
        Matcher<View> itemView = allOf(withParent(withRecyclerView(R.id.start_grid)),
                withChild(allOf(withId(identifyingView), identifyingMatcher)));
        return Espresso.onView(allOf(isDescendantOfA(itemView), childMatcher));
    }
}

和示例用法:

onRecyclerItemView(R.id.item_title, withText("Test"),  withId(R.id.item_content))
    .matches(check(withText("Test Content")));

您應該使用自定義 ViewAction:

public void clickOnImageViewAtRow(int position) {
    onView(withId(R.id.recycler_view)).perform(RecyclerViewActions.actionOnItemAtPosition(position, new ClickOnImageView()));
}

public class ClickOnImageView implements ViewAction{
    ViewAction click = click();

    @Override
    public Matcher<View> getConstraints() {
        return click.getConstraints();
    }

    @Override
    public String getDescription() {
        return " click on custom image view";
    }

    @Override
    public void perform(UiController uiController, View view) {
        click.perform(uiController, view.findViewById(R.id.imageView));
    }
}

我找到了兩種方法:

  1. 假設您在 RecyclerView 中的每個項目都有一個 ID 為“R.id.description”的文本視圖。 您可以這樣做以匹配特定的孩子:

onView(allOf(withId(R.id.place_description),withText("what"))).perform(click());

  1. 來自 Android 測試 Codelab 的教程https://codelabs.developers.google.com/codelabs/android-testing/#0

`

public Matcher<View> withItemText(final String itemText) {
        checkArgument(!TextUtils.isEmpty(itemText),"cannot be null");
        return new TypeSafeMatcher<View>() {
            @Override
            protected boolean matchesSafely(View item) {
                return allOf(isDescendantOfA(isAssignableFrom(RecyclerView.class)),withText(itemText)).matches(item);
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("is descendant of a RecyclerView with text" + itemText);
            }
        };
    }

`

然后,這樣做:

onView(withItemText("what")).perform(click());

與上面相同的答案,但是由於您必須提供 Viewholder 類型,因此進行了一些小的修改

使用 RecyclerViewActions

fun tapOnRecyclerView(@IdRes resId: Int , position: Int) = onView(withId(resId))
        .perform(actionOnItemAtPosition<RecyclerView.ViewHolder>(position, click()));

並將此庫包含在您的項目中,請使用此

androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"

更喜歡使用此鏈接中的最新濃縮咖啡版本

您不需要添加“testing-support-lib”,也不需要添加“espresso:espresso-core”。 當添加“espresso:espresso-contrib”時,它們是可傳遞的。

建造等級

dependencies {
    androidTestCompile 'com.android.support.test:runner:0.3'
    androidTestCompile 'com.android.support.test:rules:0.3'
    androidTestCompile 'com.android.support.test.espresso:espresso-contrib:2.2'
}

用法

onView(withId(R.id.recyclerView)).perform(
            RecyclerViewActions.actionOnItemAtPosition(0, click()));

我遵循了@Gabor 的回答,但是當我包含這些庫時,我達到了 dex 限制!

所以,我刪除了庫,添加了這個getInstrumentation().waitForIdleSync(); 然后只是調用onView(withId...))...

完美運行。

在您的情況下,您將擁有多個具有相同 ID 的圖像視圖,因此您必須弄清楚如何選擇特定列表項。

正如我在這里發布的那樣您可以實現您的自定義RecyclerView匹配器。 假設您有RecyclerView ,其中每個元素都有您要匹配的主題:

public static Matcher<RecyclerView.ViewHolder> withItemSubject(final String subject) {
    Checks.checkNotNull(subject);
    return new BoundedMatcher<RecyclerView.ViewHolder, MyCustomViewHolder>(
            MyCustomViewHolder.class) {

        @Override
        protected boolean matchesSafely(MyCustomViewHolder viewHolder) {
            TextView subjectTextView = (TextView)viewHolder.itemView.findViewById(R.id.subject_text_view_id);

            return ((subject.equals(subjectTextView.getText().toString())
                    && (subjectTextView.getVisibility() == View.VISIBLE)));
        }

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

和用法:

onView(withId(R.id.my_recycler_view_id)
    .perform(RecyclerViewActions.actionOnHolderItem(withItemSubject("My subject"), click()));

基本上你可以匹配任何你想要的。 在這個例子中,我們使用了主題TextView但它可以是RecyclerView項目中的任何元素。

需要澄清的另一件事是檢查可見性(subjectTextView.getVisibility() == View.VISIBLE) 我們需要它,因為有時RecyclerView其他視圖可以具有相同的主題,但它會與View.GONE 通過這種方式,我們避免了自定義匹配器的多次匹配,並且只針對實際顯示我們主題的項目。

使用此代碼,您可以滾動回收站視圖以找到您的項目 withText 並對其執行單擊或其他操作。

依賴

androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0'

代碼

@Test
public void scrollRecyclerViewAndClick() {
    onView(withId(R.id.recycler_view)).
            perform(RecyclerViewActions.
            actionOnItem(withText("specific string"), click()));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM