使用浓缩咖啡进行回收器视图UI测试,这是一个错误吗?



我的目标是测试RecyclerView滚动。当我执行示例代码时,会发生此错误:

E/TestRunner: androidx.test.espresso.PerformException: Error performing 'scroll RecyclerView to position: 17' on view 'with id: com.jakchang.hwahae:id/recyclerView'.
at androidx.test.espresso.PerformException$Builder.build(PerformException.java:84)
blabla ~~
Caused by: java.lang.RuntimeException: Action will not be performed because the target view does not match one or more of the following constraints:
(is assignable from class: class androidx.recyclerview.widget.RecyclerView and is displayed on the screen to the user)
Target view: "RecyclerView{id=2131296427, res-name=recyclerView, visibility=VISIBLE, width=1080, height=0, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=true, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams@209ca0a, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=90.0, child-count=0}"

我一直在寻找这个问题,但找不到任何可以解决它的东西。这是我的代码。

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Rule
@JvmField
val mainActivity = ActivityTestRule(MainActivity::class.java)
@Test
fun useAppContext() {
//mainActivity.launchActivity(Intent())
Espresso.onView(ViewMatchers.withId(R.id.recyclerView)) 
.perform(RecyclerViewActions.scrollToPosition<RecyclerView.ViewHolder>(17))
Thread.sleep(10000)
}
}

根据错误日志RecyclerView{..., child-count=0},看起来您的视图正在异步加载数据,并且回收器视图操作的调用过早。修复它的最简单方法是在操作之前调用Thread.sleep(...)

或者,您可以在测试用例中使用 Espresso 中的IdlingResource

fun waitUntil(matcher: Matcher<View>): ViewAction = object : ViewAction {
override fun getConstraints(): Matcher<View> {
return any(View::class.java)
}
override fun getDescription(): String {
return StringDescription().let {
matcher.describeTo(it)
"wait until: $it"
}
}
override fun perform(uiController: UiController, view: View) {
if (!matcher.matches(view)) {
ViewPropertyChangeCallback(matcher, view).run {
try {
IdlingRegistry.getInstance().register(this)
view.viewTreeObserver.addOnDrawListener(this)
uiController.loopMainThreadUntilIdle()
} finally {
view.viewTreeObserver.removeOnDrawListener(this)
IdlingRegistry.getInstance().unregister(this)
}
}
}
}
}

接下来,您必须创建一个自定义RecyclerView匹配器来检查它是否为空:

fun hasItemCount(itemCount: Matcher<Int>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description) {
description.appendText("has item count: ")
itemCount.describeTo(description)
}
override fun matchesSafely(view: RecyclerView): Boolean {
return view.adapter?.let {
itemCount.matches(it.itemCount)
} ?: false
}
}
}

然后,您可以同时使用操作和匹配器来等待RecyclerView填充或准备就绪:

onView(withId(R.id.recyclerView)).perform(
waitUntil(hasItemCount(greaterThan(0))),
RecyclerViewActions.scrollToPosition<RecyclerView.ViewHolder>(17)
)

相关内容

最新更新