使用Espresso测试可绘制的更改

时间:2015-11-17 17:34:10

标签: android android-espresso

我是Espresso测试的新手,但似乎没有办法测试可绘制的更改。

我有一个教程是ImageView Drawable幻灯片,隐藏在'半透明的TextView。在我的测试中,我想确保在按下下一个按钮时,已在教程Drawable中插入了正确的ImageView

没有默认Matcher来检查Drawable,所以我开始使用https://stackoverflow.com/a/28785178/981242编写自己的ImageView。很遗憾,由于无法检索Drawable的有效matchesSafely()的ID,我无法完成Drawable实施。

这不是测试活跃-movflags empty_moov+default_base_moof 的唯一用例。人们通常在这种情况下使用的工具是什么?

7 个答案:

答案 0 :(得分:10)

我不想比较位图,而是遵循这个答案的建议:https://stackoverflow.com/a/14474954/1396068

设置图像视图的drawable时,还会将可绘制ID存储在其setTag(R.drawable.your_drawable)的标记中。然后使用Espresso的withTagValue(equalTo(R.drawable.your_drawable))匹配器检查正确的标记。

答案 1 :(得分:9)

请查看我找到的本教程。 似乎工作得很好https://medium.com/@dbottillo/android-ui-test-espresso-matcher-for-imageview-1a28c832626f#.4snjg8frw

以下是复制意大利面的摘要; - )

public class DrawableMatcher extends TypeSafeMatcher<View> {

    private final int expectedId;
    String resourceName;

    public DrawableMatcher(int expectedId) {
        super(View.class);
        this.expectedId = expectedId;
    }

    @Override
    protected boolean matchesSafely(View target) {
        if (!(target instanceof ImageView)){
            return false;
        }
        ImageView imageView = (ImageView) target;
        if (expectedId < 0){
            return imageView.getDrawable() == null;
        }
        Resources resources = target.getContext().getResources();
        Drawable expectedDrawable = resources.getDrawable(expectedId);
        resourceName = resources.getResourceEntryName(expectedId);

        if (expectedDrawable == null) {
            return false;
        }

        Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        Bitmap otherBitmap = ((BitmapDrawable) expectedDrawable).getBitmap();
        return bitmap.sameAs(otherBitmap);
    }


    @Override
    public void describeTo(Description description) {
        description.appendText("with drawable from resource id: ");
        description.appendValue(expectedId);
        if (resourceName != null) {
            description.appendText("[");
            description.appendText(resourceName);
            description.appendText("]");
        }
    }
}

请注意,这只适用于DrawableBitmapDrawable的情况。如果您还有VectorDrawable或其他Drawable,则必须检查此内容(imageView.getDrawable() instanceOf XXXDrawable)并从中获取位图。除了你有一些简单的Drawable,你只需要一种颜色就可以进行比较。

要获取VectorDrawable的位图,例如你必须将VectorDrawable绘制到画布并将其保存到位图(当VectorDrawable着色时我遇到了一些麻烦)。 如果你有一个StateListDrawable,你可以得到所选状态的Drawable并重复你的if instanceOf级联。 对于其他Drawable类型,我没有任何经验,抱歉!

答案 2 :(得分:6)

有一个要点包含来自Frankie SardowithBackground()withCompoundDrawable()withImageDrawable()匹配器。所有归功于他。

关于图像ID - 您可以键入R.drawable.image_name,然后将自动检索drawable的ID。

答案 3 :(得分:3)

基于@wolle和@FreewheelNat的帮助,用于比较(Vector)Drawable:

public static Matcher<View> withDrawableId(@DrawableRes final int id) {
    return new DrawableMatcher(id);
}


public static class DrawableMatcher extends TypeSafeMatcher<View> {

    private final int expectedId;
    private String resourceName;

    public DrawableMatcher(@DrawableRes int expectedId) {
        super(View.class);
        this.expectedId = expectedId;
    }

    @Override
    protected boolean matchesSafely(View target) {
        if (!(target instanceof ImageView)) {
            return false;
        }
        ImageView imageView = (ImageView) target;
        if (expectedId < 0) {
            return imageView.getDrawable() == null;
        }
        Resources resources = target.getContext().getResources();
        Drawable expectedDrawable = resources.getDrawable(expectedId);
        resourceName = resources.getResourceEntryName(expectedId);
        if (expectedDrawable != null && expectedDrawable.getConstantState() != null) {
            return expectedDrawable.getConstantState().equals(
                    imageView.getDrawable().getConstantState()
            );
        } else {
            return false;
        }
    }


    @Override
    public void describeTo(Description description) {
        description.appendText("with drawable from resource id: ");
        description.appendValue(expectedId);
        if (resourceName != null) {
            description.appendText("[");
            description.appendText(resourceName);
            description.appendText("]");
        }
    }
}

答案 4 :(得分:1)

这是@drakeet答案的Kotlin版本,并做了一些修改。

class DrawableMatcher(private val targetContext: Context,
                  @param:DrawableRes private val expectedId: Int) : TypeSafeMatcher<View>(View::class.java) {

override fun matchesSafely(target: View): Boolean {
    val drawable: Drawable? = when(target) {
        is ActionMenuItemView -> target.itemData.icon
        is ImageView -> target.drawable
        else -> null
    }
    requireNotNull(drawable)
    
    val resources: Resources = target.context.resources
    val expectedDrawable: Drawable? = resources.getDrawable(expectedId, targetContext.theme)
    return expectedDrawable?.constantState?.let { it == drawable.constantState } ?: false
}

override fun describeTo(description: Description) {
    description.appendText("with drawable from resource id: $expectedId")
    targetContext.resources.getResourceEntryName(expectedId)?.let { description.appendText("[$it]") }
}

}

答案 5 :(得分:0)

我接受@wolle的答案是有效的,但我想承认,即使对于Java,它甚至可以更简单。它可以转换为static function(或Kotlin中的companion)并清除一些已弃用的代码

无论如何,Kotlin的代码压缩 - 不推荐使用的解决方案是这样的:

    fun drawableIsCorrect(@DrawableRes drawableResId: Int): Matcher<View> {
        return object : TypeSafeMatcher<View>() {
            override fun describeTo(description: Description) {
                description.appendText("with drawable from resource id: ")
                description.appendValue(drawableResId)
            }

            override fun matchesSafely(target: View?): Boolean {
                if (target !is ImageView) {
                    return false
                }
                if (drawableResId < 0) {
                    return target.drawable == null
                }
                val expectedDrawable = ContextCompat.getDrawable(target.context, drawableResId)
                        ?: return false

                val bitmap = (target.drawable as BitmapDrawable).bitmap
                val otherBitmap = (expectedDrawable as BitmapDrawable).bitmap
                return bitmap.sameAs(otherBitmap)
            }
        }
    }

22行vs 44,嗯?

答案 6 :(得分:0)

我已经在这里回答了类似的话题:Get the ID of a drawable in ImageView。 该方法基于在自定义LayoutInflater中使用指定的资源ID标记视图。整个过程由一个简单的库TagView自动完成。它对于Espresso测试尤其方便,因为您无需手动标记项目中的每个视图。实际上,除了在运行时设置一些drawable之外,您不需要更改任何内容。在这种情况下,您需要查看Tagging in runtime部分。

因此,您可以仅通过ID来比较两个drawable:

onView(withId(R.id.imageview)).check(assertTagKeyValue(
               ViewTag.IMAGEVIEW_SRC.id, android.R.drawable.ic_media_play));

自定义Espresso声明assertTagKeyValue可用here