如何在 Espresso 中测试 ActionMenuItemView 的图标

Posted

技术标签:

【中文标题】如何在 Espresso 中测试 ActionMenuItemView 的图标【英文标题】:How to test ActionMenuItemView's icon in Espresso 【发布时间】:2016-03-07 08:37:34 【问题描述】:

我在操作栏中有一个按钮,其图标根据布尔值进行更改。我想检查使用了哪个可绘制资源。

这里是更改图标的代码:

@Override
public void onPrepareOptionsMenu(Menu menu) 
    super.onPrepareOptionsMenu(menu);
    MenuItem item = menu.findItem(R.id.menu_favorite);
    if(mIsFavorite)
        item.setIcon(R.drawable.ab_icon_on);
    else
        item.setIcon(R.drawable.ab_icon_off);

需要更换图标时,菜单失效:

// request menu update
supportInvalidateOptionsMenu();

最后,我要检查结果的浓缩咖啡代码:

@Test
public void action_setUnsetFavorite() 
    // check favorite off
    onView(withImageDrawable(R.drawable.ab_icon_off))
            .check(matches(isDisplayed()));

    // click favorite button
    onView(withId(R.id.menu_favorite))
            .perform(click());

    // check favorite on
    onView(withImageDrawable(R.drawable.ab_icon_on))
            .check(matches(isDisplayed()));

请注意,我使用的是 here 找到的自定义匹配器。

【问题讨论】:

【参考方案1】:

我不能 100% 确定匹配器的工作原理以及这是否是最佳响应,但使用稍微不同版本的方法肯定会奏效。

问题是当前的匹配器只适用于 ImageViews。 ActionMenuItemView 实际上是 textView 的子类,所以不会匹配,它也没有 getDrawable() 的方法。

请注意,这仍然需要与原帖相同的Bitmap 方法。

public static Matcher<View> withActionIconDrawable(@DrawableRes final int resourceId) 
    return new BoundedMatcher<View, ActionMenuItemView>(ActionMenuItemView.class) 
        @Override
        public void describeTo(final Description description) 
            description.appendText("has image drawable resource " + resourceId);
        

        @Override
        public boolean matchesSafely(final ActionMenuItemView actionMenuItemView) 
            return sameBitmap(actionMenuItemView.getContext(), actionMenuItemView.getItemData().getIcon(), resourceId);
        
    ;

【讨论】:

注意:这也适用于 BottomNavigationView,使用 BottomNavigationItemView 而不是 ActionMenuItemView 如何点击这个确切的项目? @Jack' 我也​​在使用 BottomNavigationItemView,我想知道如何单击在该匹配器中找到的项目【参考方案2】:

@Barry Irvine 的回答非常有帮助。只是想澄清是否有人想知道如何在 Espresso 测试中使用给定的 Matcher 方法。 (科特林)

第 1 步:从问题中提到的 link 创建一个新文件 CustomMatchers。 (包括sameBitmap 方法,但是,查看cmets,修改了sameBitmap 方法)

您可以直接在测试文件中添加该方法,但将其添加到不同的文件中将有助于在您需要测试菜单项图标时重新使用它。

作为参考,这是我的CustomMatchers 文件的样子

object CustomMatchers 

fun withActionIconDrawable(@DrawableRes resourceId: Int): Matcher<View?> 
    return object : BoundedMatcher<View?, ActionMenuItemView>(ActionMenuItemView::class.java) 
        override fun describeTo(description: Description) 
            description.appendText("has image drawable resource $resourceId")
        

        override fun matchesSafely(actionMenuItemView: ActionMenuItemView): Boolean 
            return sameBitmap(
                actionMenuItemView.context,
                actionMenuItemView.itemData.icon,
                resourceId,
                actionMenuItemView
            )
        
    


private fun sameBitmap(
    context: Context,
    drawable: Drawable?,
    resourceId: Int,
    view: View
): Boolean 
    var drawable = drawable
    val otherDrawable: Drawable? = context.resources.getDrawable(resourceId)
    if (drawable == null || otherDrawable == null) 
        return false
    

    if (drawable is StateListDrawable) 
        val getStateDrawableIndex =
            StateListDrawable::class.java.getMethod(
                "getStateDrawableIndex",
                IntArray::class.java
            )
        val getStateDrawable =
            StateListDrawable::class.java.getMethod(
                "getStateDrawable",
                Int::class.javaPrimitiveType
            )
        val index = getStateDrawableIndex.invoke(drawable, view.drawableState)
        drawable = getStateDrawable.invoke(drawable, index) as Drawable
    

    val bitmap = getBitmapFromDrawable(context, drawable)
    val otherBitmap = getBitmapFromDrawable(context, otherDrawable)
    return bitmap.sameAs(otherBitmap)


private fun getBitmapFromDrawable(context: Context?, drawable: Drawable): Bitmap 
    val bitmap: 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
 

第 2 步:在测试中使用匹配器

 onView(withId(R.id.menu_item_id))
        .check(matches(CustomMatchers.withActionIconDrawable(R.drawable.ic_favorite_border)))

【讨论】:

以上是关于如何在 Espresso 中测试 ActionMenuItemView 的图标的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Espresso 中测试 ActionMenuItemView 的图标

如何使用 Espresso 测试特定活动?

Espresso:如何测试 ImageButton 的背景可绘制对象

如何在 espresso UI 测试中检查动态文本

Espresso:如何测试 SwipeRefreshLayout?

如何使用 Espresso 测试片段是不是可见