Espresso - 检查特定图像的 recyclerview 位置
Espresso - checking recyclerview position for specific image
我很难弄清楚如何使用 espresso 测试某个图像是否显示在 recyclerview 中的某个位置。我有一个人的列表,当其中一个被选中时,我会在 recyclerview 中他的图像周围显示一个选定的指示器。所以我想检查,例如,位置 0 是否显示此指示器。我正在尝试的是:
fun test(position: Int, @DrawableRes res: Int): ViewInteraction {
return onView(withId(recyclerViewId)).check(matches(hasItemAtPosition(position, hasBackground(res))))
}
private fun hasItemAtPosition(position: Int, matcher: Matcher<View>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("has item at position $position : ")
matcher.describeTo(description)
}
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
?: return false
return matcher.matches(viewHolder.itemView)
}
}
}
如果我使用 withText 而不是 withBackground 并匹配项目的文本,此代码工作正常。
我收到的错误如下所示:
androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'has item at position 0 : has background with drawable ID: 2131231310' doesn't match the selected view.
Expected: has item at position 0 : has background with drawable ID: 2131231310
我对意式浓缩咖啡和一般测试有点陌生,所以希望有人有任何建议。
更新:
测试方法在自定义中class我看起来像这样:
class RecyclerViewWait(@IdRes val recyclerViewId: Int) {
test()
hasItemAtPosition()
}
所以这两个方法也在那里(上面的那些)
我从另一个 class 给他们打电话,像这样:
override fun doesPositionContainImageInList(position: Int, imageRes: Int): ViewInteraction {
return RecyclerViewWait(R.id.recyclerViewTest).checkBackground(position, imageRes)
return 中的哪个是从我的机器人 class 中调用的,如下所示:
fun isImageShown(): Boolean {
return viewFinder.doesPositionContainImageInList(
0,
R.drawable.ic_selected_avatar
).isDisplayed()
}
我希望这是有道理的。
您的自定义匹配器仅匹配hasBackground
和viewHolder.itemView
,这是一个根视图适配器项,意味着如果根视图的背景不匹配,匹配器将失败。
如果其中一个子视图包含背景,那么也许您应该用 hasDescendant
包装匹配器,这允许匹配器匹配项目中的所有子视图:
val hasDescendantWithBackground = hasDescendant(hasBackground(res))
onView(withId(recyclerViewId)).check(matches(
hasItemAtPosition(position, hasDescendantWithBackground)))
此外,如果位置在屏幕外(视图尚未布局),findViewHolderForAdapterPosition
可能无法在您的匹配器中正常工作。
我的解决方案最终是这样的:
fun checkBackground(position: Int, @DrawableRes imageRes: Int): ViewInteraction {
return onView(withId(recyclerViewId))
.check(matches(hasItemAtPosition(position, hasDescendant(withDrawable(imageRes)))))
}
private fun hasItemAtPosition(position: Int, matcher: Matcher<View>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("has item at position $position : ")
matcher.describeTo(description)
}
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
?: return false
return matcher.matches(viewHolder.itemView)
}
}
}
private fun withDrawable(@DrawableRes resourceId: Int): Matcher<View> {
return DrawableMatcher(resourceId)
}
private class DrawableMatcher(private val expectedId: Int) : TypeSafeMatcher<View>() {
@Suppress("ReturnCount")
override fun matchesSafely(target: View): Boolean {
if (target !is ImageView || target.visibility == View.GONE) {
return false
}
if (expectedId < 0) {
return target.drawable == null
}
val resources = target.context.resources
val expectedDrawable: Drawable =
ResourcesCompat.getDrawable(resources, expectedId, target.context.theme)
?: return false
val bitmap = getBitmap(target.drawable)
val otherBitmap = getBitmap(expectedDrawable)
return bitmap.sameAs(otherBitmap)
}
private fun getBitmap(drawable: Drawable): Bitmap {
val bitmap = Bitmap.createBitmap(
drawable.intrinsicWidth,
drawable.intrinsicHeight, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
override fun describeTo(description: Description?) {
description?.appendText("isMatchingDrawableResource")
}
}
有了这个我只问 checkBackground 我想检查的位置和 imageRes 是否存在。我也在检查它是否在更下方可见。我尝试在代码中进一步使用 Espresso 中的 isDisplayed,但不知何故不起作用。
我很难弄清楚如何使用 espresso 测试某个图像是否显示在 recyclerview 中的某个位置。我有一个人的列表,当其中一个被选中时,我会在 recyclerview 中他的图像周围显示一个选定的指示器。所以我想检查,例如,位置 0 是否显示此指示器。我正在尝试的是:
fun test(position: Int, @DrawableRes res: Int): ViewInteraction {
return onView(withId(recyclerViewId)).check(matches(hasItemAtPosition(position, hasBackground(res))))
}
private fun hasItemAtPosition(position: Int, matcher: Matcher<View>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("has item at position $position : ")
matcher.describeTo(description)
}
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
?: return false
return matcher.matches(viewHolder.itemView)
}
}
}
如果我使用 withText 而不是 withBackground 并匹配项目的文本,此代码工作正常。
我收到的错误如下所示:
androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'has item at position 0 : has background with drawable ID: 2131231310' doesn't match the selected view.
Expected: has item at position 0 : has background with drawable ID: 2131231310
我对意式浓缩咖啡和一般测试有点陌生,所以希望有人有任何建议。
更新:
测试方法在自定义中class我看起来像这样:
class RecyclerViewWait(@IdRes val recyclerViewId: Int) {
test()
hasItemAtPosition()
}
所以这两个方法也在那里(上面的那些)
我从另一个 class 给他们打电话,像这样:
override fun doesPositionContainImageInList(position: Int, imageRes: Int): ViewInteraction {
return RecyclerViewWait(R.id.recyclerViewTest).checkBackground(position, imageRes)
return 中的哪个是从我的机器人 class 中调用的,如下所示:
fun isImageShown(): Boolean {
return viewFinder.doesPositionContainImageInList(
0,
R.drawable.ic_selected_avatar
).isDisplayed()
}
我希望这是有道理的。
您的自定义匹配器仅匹配hasBackground
和viewHolder.itemView
,这是一个根视图适配器项,意味着如果根视图的背景不匹配,匹配器将失败。
如果其中一个子视图包含背景,那么也许您应该用 hasDescendant
包装匹配器,这允许匹配器匹配项目中的所有子视图:
val hasDescendantWithBackground = hasDescendant(hasBackground(res))
onView(withId(recyclerViewId)).check(matches(
hasItemAtPosition(position, hasDescendantWithBackground)))
此外,如果位置在屏幕外(视图尚未布局),findViewHolderForAdapterPosition
可能无法在您的匹配器中正常工作。
我的解决方案最终是这样的:
fun checkBackground(position: Int, @DrawableRes imageRes: Int): ViewInteraction {
return onView(withId(recyclerViewId))
.check(matches(hasItemAtPosition(position, hasDescendant(withDrawable(imageRes)))))
}
private fun hasItemAtPosition(position: Int, matcher: Matcher<View>): Matcher<View> {
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("has item at position $position : ")
matcher.describeTo(description)
}
override fun matchesSafely(recyclerView: RecyclerView): Boolean {
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position)
?: return false
return matcher.matches(viewHolder.itemView)
}
}
}
private fun withDrawable(@DrawableRes resourceId: Int): Matcher<View> {
return DrawableMatcher(resourceId)
}
private class DrawableMatcher(private val expectedId: Int) : TypeSafeMatcher<View>() {
@Suppress("ReturnCount")
override fun matchesSafely(target: View): Boolean {
if (target !is ImageView || target.visibility == View.GONE) {
return false
}
if (expectedId < 0) {
return target.drawable == null
}
val resources = target.context.resources
val expectedDrawable: Drawable =
ResourcesCompat.getDrawable(resources, expectedId, target.context.theme)
?: return false
val bitmap = getBitmap(target.drawable)
val otherBitmap = getBitmap(expectedDrawable)
return bitmap.sameAs(otherBitmap)
}
private fun getBitmap(drawable: Drawable): Bitmap {
val bitmap = Bitmap.createBitmap(
drawable.intrinsicWidth,
drawable.intrinsicHeight, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
override fun describeTo(description: Description?) {
description?.appendText("isMatchingDrawableResource")
}
}
有了这个我只问 checkBackground 我想检查的位置和 imageRes 是否存在。我也在检查它是否在更下方可见。我尝试在代码中进一步使用 Espresso 中的 isDisplayed,但不知何故不起作用。