NoMatchingRootException 带有自定义吐司的浓缩咖啡
NoMatchingRootException Espresso with custom Toast
我从 Espresso 开始,我有一个自定义 Toast
,当用户输入错误时我会显示它(我知道我可以使用 EditText.setError(),但那是就是这样)。
这是 Toast 的代码
private static void showToast(Context context, String message, boolean isError) {
if (context != null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
TextView toastView = (TextView) inflater.inflate(R.layout.error_toast_layout, null);
if (!isError) {
toastView.setBackgroundColor(context.getResources().getColor(R.color.alert_positive));
}
toastView.setText(message);
Toast errorToast = new Toast(context);
errorToast.setGravity(Gravity.TOP, 0, 0);
errorToast.setDuration(Toast.LENGTH_SHORT);
errorToast.setView(toastView);
errorToast.show();
}
}
我正在写一个小 UI 测试,它将断言当用户输入错误的输入时显示正确的 Toasts
这是测试
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ForgotPasswordTest extends BaseEspressoTest<ForgotPasswordActivity> {
@Test
public void testEmailNotEntered() {
onView(withId(R.id.email_et)).perform(typeText("w"), closeSoftKeyboard());
onView(withId(R.id.btn_submit)).perform(click());
onView(withText(R.string.incorrect_email_dialog)).inRoot(withDecorView(not(mActivityRule.getActivity().getWindow().getDecorView()))).check(matches(isDisplayed()));
}
}
如果我将自定义 Toast 替换为常规 Toast,则效果很好,但当我用我的 Toast 尝试时失败。我可以看到测试期间正在显示 Toast。
这是错误:
android.support.test.espresso.NoMatchingRootException: Matcher 'with
decor view not
<com.android.internal.policy.impl.PhoneWindow$DecorView{3852d97
V.ED.... R....... 0,0-1080,1920}>' did not match any of the following
roots:
[Root{application-window-token=android.view.ViewRootImpl$W@2d629b84,
window-token=android.view.ViewRootImpl$W@2d629b84,
has-window-focus=true, layout-params-type=1,
layout-params-string=WM.LayoutParams{(0,0)(fillxfill) sim=#22 ty=1
fl=#8d810100 pfl=0x8 wanim=0x1030461 surfaceInsets=Rect(0, 0 - 0, 0)},
decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=1080,
height=1920, has-focus=true, has-focusable=true,
has-window-focus=true, is-clickable=false, is-enabled=true,
is-focused=false, is-focusable=false, is-layout-requested=false,
is-selected=false, root-is-layout-requested=false,
has-input-connection=false, x=0.0, y=0.0, child-count=1}}]
我也尝试过匹配 Toast,因为它应该是焦点:
onView(withText(R.string.incorrect_email_dialog))
.inRoot(isFocusable()).check(matches(isDisplayed()));
但这只是说它无法在视图层次结构中找到它:
No views in hierarchy found matching: with string from resource id:
<2131165635>[incorrect_email_dialog] value: Please enter a valid email
您可以尝试使用下面给出的 CustomToastMatcher:
import android.os.IBinder;
import android.support.test.espresso.Root;
import android.view.WindowManager;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
public class ToastMatcher extends TypeSafeMatcher<Root> {
@Override public void describeTo(Description description) {
description.appendText("is toast");
}
@Override public boolean matchesSafely(Root root) {
int type = root.getWindowLayoutParams().get().type;
if ((type == WindowManager.LayoutParams.TYPE_TOAST)) {
IBinder windowToken = root.getDecorView().getWindowToken();
IBinder appToken = root.getDecorView().getApplicationWindowToken();
if (windowToken == appToken) {
//means this window isn't contained by any other windows.
}
}
return false;
}
}
在这样的测试用例中使用它:
onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
.check(matches(isDisplayed()));
其他参考:
http://baroqueworksdev.blogspot.de/2015/03/how-to-check-toast-window-on-android.html
我从 Espresso 开始,我有一个自定义 Toast
,当用户输入错误时我会显示它(我知道我可以使用 EditText.setError(),但那是就是这样)。
这是 Toast 的代码
private static void showToast(Context context, String message, boolean isError) {
if (context != null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
TextView toastView = (TextView) inflater.inflate(R.layout.error_toast_layout, null);
if (!isError) {
toastView.setBackgroundColor(context.getResources().getColor(R.color.alert_positive));
}
toastView.setText(message);
Toast errorToast = new Toast(context);
errorToast.setGravity(Gravity.TOP, 0, 0);
errorToast.setDuration(Toast.LENGTH_SHORT);
errorToast.setView(toastView);
errorToast.show();
}
}
我正在写一个小 UI 测试,它将断言当用户输入错误的输入时显示正确的 Toasts
这是测试
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ForgotPasswordTest extends BaseEspressoTest<ForgotPasswordActivity> {
@Test
public void testEmailNotEntered() {
onView(withId(R.id.email_et)).perform(typeText("w"), closeSoftKeyboard());
onView(withId(R.id.btn_submit)).perform(click());
onView(withText(R.string.incorrect_email_dialog)).inRoot(withDecorView(not(mActivityRule.getActivity().getWindow().getDecorView()))).check(matches(isDisplayed()));
}
}
如果我将自定义 Toast 替换为常规 Toast,则效果很好,但当我用我的 Toast 尝试时失败。我可以看到测试期间正在显示 Toast。
这是错误:
android.support.test.espresso.NoMatchingRootException: Matcher 'with decor view not <com.android.internal.policy.impl.PhoneWindow$DecorView{3852d97 V.ED.... R....... 0,0-1080,1920}>' did not match any of the following roots: [Root{application-window-token=android.view.ViewRootImpl$W@2d629b84, window-token=android.view.ViewRootImpl$W@2d629b84, has-window-focus=true, layout-params-type=1, layout-params-string=WM.LayoutParams{(0,0)(fillxfill) sim=#22 ty=1 fl=#8d810100 pfl=0x8 wanim=0x1030461 surfaceInsets=Rect(0, 0 - 0, 0)}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=true, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}]
我也尝试过匹配 Toast,因为它应该是焦点:
onView(withText(R.string.incorrect_email_dialog))
.inRoot(isFocusable()).check(matches(isDisplayed()));
但这只是说它无法在视图层次结构中找到它:
No views in hierarchy found matching: with string from resource id: <2131165635>[incorrect_email_dialog] value: Please enter a valid email
您可以尝试使用下面给出的 CustomToastMatcher:
import android.os.IBinder;
import android.support.test.espresso.Root;
import android.view.WindowManager;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
public class ToastMatcher extends TypeSafeMatcher<Root> {
@Override public void describeTo(Description description) {
description.appendText("is toast");
}
@Override public boolean matchesSafely(Root root) {
int type = root.getWindowLayoutParams().get().type;
if ((type == WindowManager.LayoutParams.TYPE_TOAST)) {
IBinder windowToken = root.getDecorView().getWindowToken();
IBinder appToken = root.getDecorView().getApplicationWindowToken();
if (windowToken == appToken) {
//means this window isn't contained by any other windows.
}
}
return false;
}
}
在这样的测试用例中使用它:
onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
.check(matches(isDisplayed()));
其他参考: