比较两个VectorDrawables在Kaspresso - Android中失败



我正在尝试使用Kaspresso进行测试,我正在检查视图是否具有特定的drawable方法:

withId<KImageView>(R.id.criticalErrorImage) {
hasDrawable(R.drawable.error_graphic)
}

与PNG工作得很好,而比较图像存储在imageView和恢复和VectorDrawable失败。

检查的文件是这个。

特别是这部分代码:

var expectedDrawable: Drawable? = drawable ?: getResourceDrawable(resId)?.mutate()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && expectedDrawable != null) {
expectedDrawable = DrawableCompat.wrap(expectedDrawable).mutate()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tintColorId?.let { tintColorId ->
val tintColor = getResourceColor(tintColorId)
expectedDrawable?.apply {
setTintList(ColorStateList.valueOf(tintColor))
setTintMode(PorterDuff.Mode.SRC_IN)
}
}
}
if (expectedDrawable == null) {
return false
}
val convertDrawable = (imageView as ImageView).drawable.mutate()
val bitmap = toBitmap?.invoke(convertDrawable) ?: convertDrawable.toBitmap()
val otherBitmap = toBitmap?.invoke(expectedDrawable) ?: expectedDrawable.toBitmap()

有趣的是,如果我通过数据绑定设置图像,它可以工作,而如果我以所有其他方式设置它则不起作用。我不明白为什么。

我在这里创建了一个POC: https://github.com/filnik/proof_of_concept

特别地,下面是测试:https://github.com/filnik/proof_of_concept/blob/master/app/src/androidTest/java/com/neato/test/POCInstrumentationTest.kt

在这里我动态设置图像:https://github.com/filnik/proof_of_concept/blob/master/app/src/main/java/com/neato/test/FirstFragment.kt

这个问题是因为实际上图像是缩放的。因此,缩放后的图像与原始图像不同。

为了避免这个问题,我使用了" changed "KImageView:

package your_package
import android.content.res.ColorStateList
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.PorterDuff
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.StateListDrawable
import android.os.Build
import android.view.View
import android.widget.ImageView
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.core.graphics.drawable.DrawableCompat
import androidx.test.espresso.DataInteraction
import androidx.test.espresso.assertion.ViewAssertions
import com.agoda.kakao.common.assertions.BaseAssertions
import com.agoda.kakao.common.builders.ViewBuilder
import com.agoda.kakao.common.utilities.getResourceColor
import com.agoda.kakao.common.utilities.getResourceDrawable
import com.agoda.kakao.common.views.KBaseView
import com.agoda.kakao.image.KImageView
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.TypeSafeMatcher
class KImageView2 : KBaseView<KImageView>, ImageViewAssertions2 {
constructor(function: ViewBuilder.() -> Unit) : super(function)
constructor(parent: Matcher<View>, function: ViewBuilder.() -> Unit) : super(parent, function)
constructor(parent: DataInteraction, function: ViewBuilder.() -> Unit) : super(parent, function)
}

interface ImageViewAssertions2 : BaseAssertions {
/**
* Checks if the view displays given drawable
*
* @param resId Drawable resource to be matched
* @param toBitmap Lambda with custom Drawable -> Bitmap converter (default is null)
*/
fun hasDrawable(@DrawableRes resId: Int, toBitmap: ((drawable: Drawable) -> Bitmap)? = null) {
view.check(ViewAssertions.matches(DrawableMatcher2(resId = resId, toBitmap = toBitmap)))
}
}

class DrawableMatcher2(
@DrawableRes private val resId: Int = -1,
@ColorRes private val tintColorId: Int? = null,
private val toBitmap: ((drawable: Drawable) -> Bitmap)? = null
) : TypeSafeMatcher<View>(View::class.java) {
override fun describeTo(desc: Description) {
desc.appendText("with drawable id $resId or provided instance")
}
override fun matchesSafely(view: View?): Boolean {
if (view !is ImageView) {
return false
}
if (resId < 0) {
return view.drawable == null
}
val bitmap = extractFromImageView(view)
view.setImageResource(resId)
val otherBitmap = extractFromImageView(view)
return bitmap?.sameAs(otherBitmap) ?: false
}
private fun extractFromImageView(view: View?): Bitmap? {
return view?.let { imageView ->
var expectedDrawable: Drawable? = getResourceDrawable(resId)?.mutate()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && expectedDrawable != null) {
expectedDrawable = DrawableCompat.wrap(expectedDrawable).mutate()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
tintColorId?.let { tintColorId ->
val tintColor = getResourceColor(tintColorId)
expectedDrawable?.apply {
setTintList(ColorStateList.valueOf(tintColor))
setTintMode(PorterDuff.Mode.SRC_IN)
}
}
}
if (expectedDrawable == null) {
return null
}
val convertDrawable = (imageView as ImageView).drawable.mutate()
toBitmap?.invoke(convertDrawable) ?: convertDrawable.toBitmap()
}
}
}
internal fun Drawable.toBitmap(): Bitmap {
if (this is BitmapDrawable && this.bitmap != null) {
return this.bitmap
}
if (this is StateListDrawable && this.getCurrent() is BitmapDrawable) {
val bitmapDrawable = this.getCurrent() as BitmapDrawable
if (bitmapDrawable.bitmap != null) {
return bitmapDrawable.bitmap
}
}
val bitmap = if (this.intrinsicWidth <= 0 || this.intrinsicHeight <= 0) {
Bitmap.createBitmap(
1,
1,
Bitmap.Config.ARGB_8888
) // Single color bitmap will be created of 1x1 pixel
} else {
Bitmap.createBitmap(this.intrinsicWidth, this.intrinsicHeight, Bitmap.Config.ARGB_8888)
}
val canvas = Canvas(bitmap)
this.setBounds(0, 0, canvas.width, canvas.height)
this.draw(canvas)
return bitmap
}

不是最干净的解决方案,但它有效。如果有人能提供更好的解决方案就太好了:-)

最新更新