Android Espresso(五) ——Custom Matcher
上一篇(Android Espresso(四)——RecyclerView)提到了使用自定义 ViewAction 来灵活应对 RecyclerView 中复杂Item测试。
这一篇讲下,在某种场景下,相同文字不同颜色或者其他属性,匹配其中一个组件进行操作,使用自定义ViewMatcher 。
自定义Matcher
在匹配一些简单的UI组件上,可以使用 BoundedMatcher 快速定义自己的 Matcher 。
static class CustomViewMatchers {
public static Matcher<View> withColoredText(final int expectedColor) {
return new BoundedMatcher<View, TextView>(TextView.class) {
@Override
public void describeTo(Description description) {
description.appendText("To find the textview with " + expectedColor + " color text");
}
@Override
protected boolean matchesSafely(TextView item) {
return expectedColor == item.getCurrentTextColor();
}
};
}
}
上述这段代码,可以快速看下如何使用 BoundedMatcher 来定义自己的 Matcher。
BoundedMatcher
先来看下 BoundedMatcher 定义。
public abstract class BoundedMatcher<T, S extends T> extends BaseMatcher<T> {
private final Class<?> expectedType;
private final Class<?>[] interfaceTypes;
public BoundedMatcher(Class<? extends S> expectedType) {
this.expectedType = checkNotNull(expectedType);
this.interfaceTypes = new Class[0];
}
public BoundedMatcher(
Class<?> expectedType, Class<?> interfaceType1, Class<?>... otherInterfaces) {
this.expectedType = checkNotNull(expectedType);
checkNotNull(otherInterfaces);
int interfaceCount = otherInterfaces.length + 1;
this.interfaceTypes = new Class[interfaceCount];
interfaceTypes[0] = checkNotNull(interfaceType1);
checkArgument(interfaceType1.isInterface());
int interfaceTypeIdx = 1;
for (Class<?> intfType : otherInterfaces) {
interfaceTypes[interfaceTypeIdx] = checkNotNull(intfType);
checkArgument(intfType.isInterface());
interfaceTypeIdx++;
}
}
protected abstract boolean matchesSafely(S item);
@Override
@SuppressWarnings({"unchecked"})
public final boolean matches(Object item) {
if (item == null) {
return false;
}
if (expectedType.isInstance(item)) {
for (Class<?> intfType : interfaceTypes) {
if (!intfType.isInstance(item)) {
return false;
}
}
return matchesSafely((S) item);
}
return false;
}
}
BoundedMatcher 本身的定义中包含了两个构造方法,第二个构造方法中可以同时传入多个需要进行匹配的类型。我们在上述实现使用的是单个参数的构造方法。
@Test
public void testCustomMatcher() throws InterruptedException {
Activity activity = activityTestRule.getActivity();
onView(withId(R.id.textview_red_text)).check(matches(withColoredText(activity.getColor(android.R.color.holo_red_dark)))).perform(click());
Thread.sleep(1000);
onView(withId(R.id.button_change_color)).check(matches(isAssignableFrom(Button.class))).perform(click());
Thread.sleep(1000);
onView(withId(R.id.textview_common_text)).check(matches(withColoredText(Color.BLUE))).perform(click());
}
这里直接使用check()方法来检查传入的颜色是否与ID匹配的TextView 颜色形同。
看下运行效果。
总结
除了 BoundedMatcher ,Espresso还提供其他诸如CustomMatcher ,TypeSafeMatcher 等可用于自定义Matcher的定义。
这篇文章中只列举了BoundedMatcher 的使用,其他Matcher的使用或执行原理,感兴趣的同学可以自己再查看下定义。
|