使用Espresso测试可绘制的更改

nuk*_*rum 12 android android-espresso

我是Espresso测试的新手,但似乎没有任何方法可以测试可绘制的更改.

我有一个教程是ImageView Drawable幻灯片'塞进'半透明的TextView.在我的测试中,我想确保当按下下一个按钮时,正确的Drawable插入教程中ImageView.

没有默认Matcher检查Drawables,所以我开始使用/sf/answers/2014962491/编写自己的.不幸的是,因为没有办法来检索的ID ImageView的活跃Drawable,我无法完成matchesSafely()执行.

这不是测试活动Drawables 的唯一用例.人们通常在这种情况下使用的工具是什么?

Fab*_*tel 10

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

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

  • 这个解决方案只有一个问题 - 您需要在生产中添加仅在测试中使用的代码,这是一个很大的禁忌。 (10认同)
  • 并且您可以删除实际背景并保留标签,您的 UI 测试仍然有效并且不会反映现实 (5认同)

wol*_*lle 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("]");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这仅适用于您Drawable的情况BitmapDrawable.如果你还有VectorDrawable其他Drawable你需要检查这个(imageView.getDrawable() instanceOf XXXDrawable)并从中获取位图.除了你有一些简单的Drawable,你只有一种颜色,你可以比较.

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


den*_*nys 8

这里是包含一个要点withBackground(),withCompoundDrawable(),withImageDrawable()从匹配器弗朗基·萨多.所有归功于他.

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


dra*_*eet 7

基于@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("]");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*lls 5

这是 @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]") }
}
}
Run Code Online (Sandbox Code Playgroud)