【问题标题】:Espresso - checking recyclerview position for specific image浓缩咖啡 - 检查特定图像的回收站视图位置
【发布时间】:2021-04-07 14:45:37
【问题描述】:

我很难弄清楚如何使用 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 RecyclerViewWait(@IdRes val recyclerViewId: Int) {

test()
hasItemAtPosition()
}

所以这两种方法也在那里(上面的那些)

我从另一个班级给他们打电话,像这样:

override fun doesPositionContainImageInList(position: Int, imageRes: Int): ViewInteraction {
    return RecyclerViewWait(R.id.recyclerViewTest).checkBackground(position, imageRes)

作为回报从我的机器人类中调用,如下所示:

fun isImageShown(): Boolean {
    return viewFinder.doesPositionContainImageInList(
        0,
        R.drawable.ic_selected_avatar
    ).isDisplayed()
}

我希望这是有道理的。

【问题讨论】:

    标签: android kotlin testing android-espresso


    【解决方案1】:

    您的自定义匹配器匹配 hasBackgroundviewHolder.itemView,这是适配器项的 根视图,这意味着如果背景为根视图不匹配。

    如果其中一个子视图包含背景,那么也许你应该用hasDescendant 包装匹配器,这允许匹配器匹配项目中的所有子视图:

    val hasDescendantWithBackground = hasDescendant(hasBackground(res))
    onView(withId(recyclerViewId)).check(matches(
        hasItemAtPosition(position, hasDescendantWithBackground)))
    

    另外,如果位置不在屏幕上,findViewHolderForAdapterPosition 可能无法在您的匹配器中正常工作(视图尚未布局)。

    【讨论】:

    • 遗憾的是这不起作用,当我这样做时仍然给我一个错误。但我认为你正在接近一些东西!
    • 是的,完全一样的错误。我不知道我是否可能要求错误地检查图像?我会尽快更新问题。
    • 我编辑了我的评论,希望你能理解这一点,看看我是不是搞砸了
    • 不确定这是否有帮助,但根据github.com/android/android-test/blob/master/espresso/core/java/…,看起来匹配器只比较BitmapDrawable,我猜你的drawable可能不是BitmapDrawable,但我不熟悉可绘制类型:(
    • 嗯,我也没有。感谢您的帮助!
    【解决方案2】:

    我的解决方案有效,结果是这样的:

    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,但不知何故不起作用。

    【讨论】:

    • 这似乎直接来自here,这很好,但不适用于向量
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    • 1970-01-01
    相关资源
    最近更新 更多