使用 Espresso 检查 RecyclerView 的每一项中的 TextView
Check TextView in each item of RecyclerView with Espresso
有一个 RecyclerView (R.id.recycler_view)。每个项目 (R.id.movie_card) 包含两个视图:ImageView 和 TextView (R.id.movie_title_text_view)。目标是与 Espresso 检查所有 recyclerview 的项目是否包含非空文本视图。请大家帮忙正确写代码
也有使用Idle。所以,开始测试RecyclerView的时刻是正确的(加载完所有数据后)。
不清楚如何断言所有 R.id.movie_title_text_view 都不为空。
完整测试方法如下:
@Rule
public ActivityTestRule activityTestRule = new ActivityTestRule(MainActivity.class);
@Test
public void GridFragmentRecycleViewTest(){
final int TESTED_VIEWHOLDERS_QUANTITY = 10;
IdlingResource componentIdlingResource = getIdlingResource();
Espresso.registerIdlingResources(componentIdlingResource);
Log.d(TAG, "GridFragmentRecycleViewTest()");
onView(withId(R.id.action_search)).perform(click());
onView(isAssignableFrom(SearchView.class)).perform(typeSearchViewText("lord")).perform(pressKey(KeyEvent.KEYCODE_ENTER));
EspressoIdlingResource.increment();
onView(withId(R.id.recycler_view)).check(new RecyclerViewItemCountAssertion(TESTED_VIEWHOLDERS_QUANTITY));
//up to here all works good
onView(allOf(withId(R.id.movie_title_text_view))).check(matches(withText(not(isEmptyString()))));
}
public static ViewAction typeSearchViewText(final String text){
return new ViewAction(){
@Override
public Matcher<View> getConstraints() {
//Ensure that only apply if it is a SearchView and if it is visible.
return allOf(isDisplayed(), isAssignableFrom(SearchView.class));
}
@Override
public String getDescription() {
return "Change view text";
}
@Override
public void perform(UiController uiController, View view) {
((SearchView) view).setQuery(text,false);
}
};
}
行:
onView(allOf(withId(R.id.movie_title_text_view))).check(匹配(withText(not(isEmptyString()))));
出现以下异常:
androidx.test.espresso.AmbiguousViewMatcherException: '(with id: com.example.myapplication3:id/movie_title_text_view)' 匹配层次结构中的多个视图。
问题视图在下方标有“****匹配****”。
查看层次结构:
+>DecorView{id=-1, visibility=VISIBLE, width=1440, height=2560, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false , is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302f8
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3}
...
此答案尚未准备好使用,但如果您没有得到其他答案,它有望帮助您朝着正确的方向前进。
- 你需要依赖 RecyclerView 寻找 view holder 的能力,并构建
围绕它的断言 (
RecyclerView.ViewHolder holder = recyclerViewInstance.findViewHolderForAdapterPosition(index);
)
- 使用
holder.itemView.findViewsWithText(listOfViews, text, FIND_VIEWS_WITH_TEXT);
或例如 holder.itemView.findViewById(yourViewId);
查找相关的视图持有者视图
- 遍历您拥有的项目并为每个项目执行上述操作
项目
您可能希望为此目的构建一些视图断言:
public static ViewAssertion hasViewWithXyzAtPosition(final int index, final CharSequence text) {
return new ViewAssertion() {
@Override
public void check(View view, NoMatchingViewException e) {
if (!(view instanceof RecyclerView)) {
throw e;
}
RecyclerView rv = (RecyclerView) view;
RecyclerView.ViewHolder holder = rv.findViewHolderForAdapterPosition(index);
//...
Assert.assertTrue(
"There's no view at index " + index + ",
...
);
}
};
}
有一个 RecyclerView (R.id.recycler_view)。每个项目 (R.id.movie_card) 包含两个视图:ImageView 和 TextView (R.id.movie_title_text_view)。目标是与 Espresso 检查所有 recyclerview 的项目是否包含非空文本视图。请大家帮忙正确写代码
也有使用Idle。所以,开始测试RecyclerView的时刻是正确的(加载完所有数据后)。
不清楚如何断言所有 R.id.movie_title_text_view 都不为空。 完整测试方法如下:
@Rule
public ActivityTestRule activityTestRule = new ActivityTestRule(MainActivity.class);
@Test
public void GridFragmentRecycleViewTest(){
final int TESTED_VIEWHOLDERS_QUANTITY = 10;
IdlingResource componentIdlingResource = getIdlingResource();
Espresso.registerIdlingResources(componentIdlingResource);
Log.d(TAG, "GridFragmentRecycleViewTest()");
onView(withId(R.id.action_search)).perform(click());
onView(isAssignableFrom(SearchView.class)).perform(typeSearchViewText("lord")).perform(pressKey(KeyEvent.KEYCODE_ENTER));
EspressoIdlingResource.increment();
onView(withId(R.id.recycler_view)).check(new RecyclerViewItemCountAssertion(TESTED_VIEWHOLDERS_QUANTITY));
//up to here all works good
onView(allOf(withId(R.id.movie_title_text_view))).check(matches(withText(not(isEmptyString()))));
}
public static ViewAction typeSearchViewText(final String text){
return new ViewAction(){
@Override
public Matcher<View> getConstraints() {
//Ensure that only apply if it is a SearchView and if it is visible.
return allOf(isDisplayed(), isAssignableFrom(SearchView.class));
}
@Override
public String getDescription() {
return "Change view text";
}
@Override
public void perform(UiController uiController, View view) {
((SearchView) view).setQuery(text,false);
}
};
}
行:
onView(allOf(withId(R.id.movie_title_text_view))).check(匹配(withText(not(isEmptyString()))));
出现以下异常: androidx.test.espresso.AmbiguousViewMatcherException: '(with id: com.example.myapplication3:id/movie_title_text_view)' 匹配层次结构中的多个视图。 问题视图在下方标有“****匹配****”。
查看层次结构: +>DecorView{id=-1, visibility=VISIBLE, width=1440, height=2560, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false , is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) ty=BASE_APPLICATION wanim=0x10302f8 fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3} ...
此答案尚未准备好使用,但如果您没有得到其他答案,它有望帮助您朝着正确的方向前进。
- 你需要依赖 RecyclerView 寻找 view holder 的能力,并构建
围绕它的断言 (
RecyclerView.ViewHolder holder = recyclerViewInstance.findViewHolderForAdapterPosition(index);
) - 使用
holder.itemView.findViewsWithText(listOfViews, text, FIND_VIEWS_WITH_TEXT);
或例如holder.itemView.findViewById(yourViewId);
查找相关的视图持有者视图
- 遍历您拥有的项目并为每个项目执行上述操作 项目
您可能希望为此目的构建一些视图断言:
public static ViewAssertion hasViewWithXyzAtPosition(final int index, final CharSequence text) {
return new ViewAssertion() {
@Override
public void check(View view, NoMatchingViewException e) {
if (!(view instanceof RecyclerView)) {
throw e;
}
RecyclerView rv = (RecyclerView) view;
RecyclerView.ViewHolder holder = rv.findViewHolderForAdapterPosition(index);
//...
Assert.assertTrue(
"There's no view at index " + index + ",
...
);
}
};
}