我正在尝试检查RecyclerView中的项目是否包含预期的图像可绘制对象。我尝试检查后代,但在获取图像视图本身的ID而不是我要查找的可绘制对象时遇到错误。
onView(new RecyclerViewMatcher(R.id.rv_sub_services).atPositionOnView(0, R.id.iv_service_image))
.check(matches(atPosition(0, hasDescendant(withId(R.drawable.eap_financial)))));
Expected: has item at position 0: has descendant: with id: 2131165345
Got: "AppCompatImageView{id=2131296664, res-name=iv_service_image, desc=Resource
type, visibility=VISIBLE, width=36...}
我也尝试过使用自定义匹配器,但这让我更加沮丧,因为当我尝试将文本与textview进行匹配时,效果很好,但是当我尝试将imageview与R.drawable id进行匹配时,效果却不佳。
我正在谈论的那个人:
public class RecyclerViewMatcher {
private final int recyclerViewId;
public RecyclerViewMatcher(int recyclerViewId) {
this.recyclerViewId = recyclerViewId;
}
public Matcher<View> atPosition(final int position) {
return atPositionOnView(position, -1);
}
public Matcher<View> atPositionOnView(final int position, final int targetViewId) {
return new TypeSafeMatcher<View>() {
View childView;
public void describeTo(Description description) {
}
public boolean matchesSafely(View view) {
if (childView == null) {
RecyclerView recyclerView = view.getRootView().findViewById(recyclerViewId);
if (recyclerView != null && recyclerView.getId() == recyclerViewId) {
childView = recyclerView.findViewHolderForAdapterPosition(position).itemView;
} else {
return false;
}
}
if (targetViewId == -1) {
return view == childView;
} else {
View targetView = childView.findViewById(targetViewId);
return view == targetView;
}
}
};
}
}
这段代码适用于textview
onView(new RecyclerViewMatcher(R.id.rv_sub_services).atPositionOnView(0, R.id.tv_title)).check(matches(withText("Financial Assistance")));
但不适用于imageview:
onView(new RecyclerViewMatcher(R.id.rv_sub_services).atPositionOnView(0, R.id.iv_service_image)).check(matches(withId(R.drawable.eap_financial));
非常感谢您的帮助。 非常感谢。
更新
添加匹配器,以在不是一个recyclerView项时比较可绘制对象,以防也可能适合此方案?
public class EspressoTestsMatchers {
public Matcher<View> withDrawable(final int resourceId) {
return new DrawableMatcher(resourceId);
}
public Matcher<View> noDrawable() {
return new DrawableMatcher(-1);
}
}
public class DrawableMatcher extends TypeSafeMatcher<View> {
private final int expectedId;
public DrawableMatcher(int resourceId) {
super(View.class);
this.expectedId = resourceId;
}
@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);
if (expectedDrawable == null) {
return false;
}
Bitmap bitmap = getBitmap(imageView.getDrawable());
Bitmap otherBitmap = getBitmap(expectedDrawable);
return bitmap.sameAs(otherBitmap);
}
private Bitmap getBitmap(Drawable drawable) {
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
@Override
public void describeTo(Description description) {
}
}
答案 0 :(得分:1)
如果您的匹配者必须在setBounds
上调用View
,我认为这是不安全,因为测试结果可能会意外更改。您可以尝试在Espresso中基于ImageView
为HasBackgroundMatcher
创建自定义匹配器:
public static Matcher<View> hasImage(int drawableId) {
return new BoundedMatcher<View, ImageView>(ImageView.class) {
@Override public void describeTo(Description description) {
description.appendText("has image with drawable ID: " + drawableId);
}
@Override protected boolean matchesSafely(ImageView view) {
return assertDrawable(view.getDrawable(), drawableId, view);
}
};
}
private static boolean compareBitmaps(Bitmap img1, Bitmap img2) {
if (img1.getWidth() == img2.getWidth() && img1.getHeight() == img2.getHeight()) {
int[] img1Pixels = new int[img1.getWidth() * img1.getHeight()];
int[] img2Pixels = new int[img2.getWidth() * img2.getHeight()];
img1.getPixels(img1Pixels, 0, img1.getWidth(), 0, 0, img1.getWidth(), img1.getHeight());
img2.getPixels(img2Pixels, 0, img2.getWidth(), 0, 0, img2.getWidth(), img2.getHeight());
return Arrays.equals(img1Pixels, img2Pixels);
}
return false;
}
private static boolean assertDrawable(Drawable actual, int expectedId, View v) {
if (!(actual instanceof BitmapDrawable)) {
return false;
}
Bitmap expectedBitmap = null;
try {
expectedBitmap = BitmapFactory.decodeResource(v.getContext().getResources(), expectedId);
if (Build.VERSION.SDK_INT >= 12) {
return ((BitmapDrawable) actual).getBitmap().sameAs(expectedBitmap);
} else {
return compareBitmaps(((BitmapDrawable) actual).getBitmap(), expectedBitmap);
}
} catch (OutOfMemoryError error) {
return false;
} finally {
if (expectedBitmap != null) {
expectedBitmap.recycle();
}
}
}
那么您可以做:
onView(new RecyclerViewMatcher(R.id.rv_sub_services).atPositionOnView(0, R.id.iv_service_image)).check(matches(hasImage(R.drawable.eap_financial));
我不确定它是否如您所愿,但祝您好运!