Android 使用浓缩咖啡测试可拉伸的变化

Android 使用浓缩咖啡测试可拉伸的变化,android,android-espresso,Android,Android Espresso,我对浓缩咖啡测试还不熟悉,但似乎没有任何方法可以测试可拉伸的变化 我有一个教程,它是一个半透明的文本视图中的图像视图可绘制幻灯片。在测试中,我希望确保按下“下一步”按钮时,正确的Drawable已插入教程的ImageView 没有默认的Matcher来检查Drawables,所以我开始使用它编写自己的代码。不幸的是,由于无法检索ImageView的活动Drawable的id,因此我无法完成matchesafely()实现 这不是测试活动Drawables的唯一用例。人们在这种情况下通常使用什么工

我对浓缩咖啡测试还不熟悉,但似乎没有任何方法可以测试可拉伸的变化

我有一个教程,它是一个半透明的
文本视图
中的
图像视图
可绘制幻灯片。在测试中,我希望确保按下“下一步”按钮时,正确的
Drawable
已插入教程的
ImageView

没有默认的
Matcher
来检查
Drawable
s,所以我开始使用它编写自己的代码。不幸的是,由于无法检索
ImageView
的活动
Drawable
的id,因此我无法完成
matchesafely()
实现


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

请查看我找到的本教程。 看起来效果不错

以下是复制面食的摘要;-)

公共类DrawableMatcher扩展了TypeSafeMatcher{
私人终审法院;
字符串资源名;
公共DrawableMatcher(int-expectedId){
super(View.class);
this.expectedId=expectedId;
}
@凌驾
受保护的布尔匹配安全(查看目标){
如果(!(ImageView的目标实例)){
返回false;
}
ImageView ImageView=(ImageView)目标;
如果(预期d<0){
返回imageView.getDrawable()==null;
}
Resources=target.getContext().getResources();
Drawable expectedDrawable=resources.getDrawable(expectedId);
resourceName=resources.getResourceEntryName(expectedId);
如果(expectedDrawable==null){
返回false;
}
位图位图=((BitmapDrawable)imageView.getDrawable()).getBitmap();
位图otherBitmap=((BitmapDrawable)expectedDrawable).getBitmap();
返回位图.sameAs(其他位图);
}
@凌驾
公共无效说明(说明){
description.appendText(“可从资源id提取:”);
说明.附录值(expectedId);
if(resourceName!=null){
说明.附录文本(“[”);
description.appendText(resourceName);
说明.附录文本(“]”);
}
}
}
请注意,这仅在
可绘制
位图可绘制
时有效。如果您还有
VectorDrawable
或其他
Drawable
,则必须检查此(
imageView.getDrawable()实例XXXDrawable
)并从中取出位图。除了你有一些简单的绘图,你只有一种颜色,或者你可以比较

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

有一个要点,其中包含来自的
withBackground()
withCompoundDrawable()
withImageDrawable()
匹配器。全归功于他


关于图像id-您可以键入
R.drawable.image\u name
,然后将自动检索可绘制图像的id。

基于@wolle和@freeweelnat的帮助,用于比较(向量)可绘制图像:

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("]");
        }
    }
}
publicstaticmatcher-drawableId(@DrawableRes-final-int-id){
返回新的DrawableMatcher(id);
}
公共静态类DrawableMatcher扩展了TypeSafeMatcher{
私人终审法院;
私有字符串resourceName;
公共DrawableMatcher(@DrawableRes int-expectedId){
super(View.class);
this.expectedId=expectedId;
}
@凌驾
受保护的布尔匹配安全(查看目标){
如果(!(ImageView的目标实例)){
返回false;
}
ImageView ImageView=(ImageView)目标;
如果(预期d<0){
返回imageView.getDrawable()==null;
}
Resources=target.getContext().getResources();
Drawable expectedDrawable=resources.getDrawable(expectedId);
resourceName=resources.getResourceEntryName(expectedId);
if(expectedDrawable!=null&&expectedDrawable.getConstantState()!=null){
返回expectedDrawable.getConstantState().equals(
imageView.getDrawable().getConstantState()
);
}否则{
返回false;
}
}
@凌驾
公共无效说明(说明){
description.appendText(“可从资源id提取:”);
说明.附录值(expectedId);
if(resourceName!=null){
说明.附录文本(“[”);
description.appendText(resourceName);
说明.附录文本(“]”);
}
}
}

我不喜欢比较位图,而是遵循以下答案的建议:


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

我接受@wolle的答案是有效的,但我想承认,即使对于Java,它也可能比这更简单。它可以转换为
静态函数
(或Kotlin中的
伴奏
),还可以清除一些不推荐使用的代码

无论如何,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)
            }
        }
    }
fun-drawableIsCorrect(@DrawableRes-drawableResId:Int):匹配器{
返回对象:TypeSafeMatcher(){
覆盖乐趣描述(描述:descripp
    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)
            }
        }
    }
onView(withId(R.id.imageview)).check(assertTagKeyValue(
               ViewTag.IMAGEVIEW_SRC.id, android.R.drawable.ic_media_play));
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]") }
}
}