[英]Android Espresso: How to check that Toast message is NOT shown?
I'm working now in my functional tests and in one of them I have to test that a toast message is NOT shown.我现在正在我的功能测试中工作,在其中一个我必须测试没有显示 toast 消息。 Considering this is the code I'm using to check if the toast message is shown (this code works):
考虑到这是我用来检查是否显示 toast 消息的代码(此代码有效):
onView(withText(R.string.my_toast_message))
.inRoot(withDecorView(not(getActivity().getWindow().getDecorView())))
.check(matches(isDisplayed()));
below you can find the code I'm using to check that a toast message is NOT shown (none of them work):您可以在下面找到我用来检查 toast 消息是否未显示的代码(它们都不起作用):
Approach one:方法一:
onView(withText(R.string.error_invalid_login))
.inRoot(withDecorView(not(getActivity().getWindow().getDecorView())))
.check(matches(not(isDisplayed())));
Approach two:方法二:
onView(withText(R.string.error_invalid_login))
.inRoot(withDecorView(not(getActivity().getWindow().getDecorView())))
.check(doesNotExist());
Any idea about how can I check that a toast message is not shown would be really appreciated :)任何有关如何检查未显示 Toast 消息的想法都将不胜感激:)
It is required to catch the case when the toast does not exist, for which a NoMatchingRootException
is thrown.需要捕获toast不存在的情况,为此抛出
NoMatchingRootException
。 Below shows the "Espresso way" of catching that.下面显示了捕捉它的“浓缩咖啡方式”。
public static Matcher<Root> isToast() {
return new WindowManagerLayoutParamTypeMatcher("is toast", WindowManager.LayoutParams.TYPE_TOAST);
}
public static void assertNoToastIsDisplayed() {
onView(isRoot())
.inRoot(isToast())
.withFailureHandler(new PassMissingRoot())
.check(matches(not(anything("toast root existed"))))
;
}
A quick (self-)test that uses the above:使用上述内容的快速(自我)测试:
@Test public void testToastMessage() {
Toast toast = createToast("Hello Toast!");
assertNoToastIsDisplayed();
toast.show();
onView(withId(android.R.id.message))
.inRoot(isToast())
.check(matches(withText(containsStringIgnoringCase("hello"))));
toast.cancel();
assertNoToastIsDisplayed();
}
private Toast createToast(final String message) {
final AtomicReference<Toast> toast = new AtomicReference<>();
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@SuppressLint("ShowToast") // will be shown later
@Override public void run() {
toast.set(Toast.makeText(InstrumentationRegistry.getContext(), message, Toast.LENGTH_LONG));
}
});
return toast.get();
}
The magical reusable helper classes:神奇的可重用助手类:
public class PassMissingRoot implements FailureHandler {
private final FailureHandler defaultHandler
= new DefaultFailureHandler(InstrumentationRegistry.getTargetContext());
@Override public void handle(Throwable error, Matcher<View> viewMatcher) {
if (!(error instanceof NoMatchingRootException)) {
defaultHandler.handle(error, viewMatcher);
}
}
}
public class WindowManagerLayoutParamTypeMatcher extends TypeSafeMatcher<Root> {
private final String description;
private final int type;
private final boolean expectedWindowTokenMatch;
public WindowManagerLayoutParamTypeMatcher(String description, int type) {
this(description, type, true);
}
public WindowManagerLayoutParamTypeMatcher(String description, int type, boolean expectedWindowTokenMatch) {
this.description = description;
this.type = type;
this.expectedWindowTokenMatch = expectedWindowTokenMatch;
}
@Override public void describeTo(Description description) {
description.appendText(this.description);
}
@Override public boolean matchesSafely(Root root) {
if (type == root.getWindowLayoutParams().get().type) {
IBinder windowToken = root.getDecorView().getWindowToken();
IBinder appToken = root.getDecorView().getApplicationWindowToken();
if (windowToken == appToken == expectedWindowTokenMatch) {
// windowToken == appToken means this window isn't contained by any other windows.
// if it was a window for an activity, it would have TYPE_BASE_APPLICATION.
return true;
}
}
return false;
}
}
The best way to test toast message in espresso is using a custom matcher:在 espresso 中测试 toast 消息的最佳方法是使用自定义匹配器:
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;
}
}
This you can use in your test case:您可以在测试用例中使用它:
Test if the Toast Message is Displayed测试是否显示 Toast 消息
onView(withText(R.string.message)).inRoot(new ToastMatcher()) .check(matches(isDisplayed()));
Test if the Toast Message is not Displayed测试是否不显示 Toast 消息
onView(withText(R.string.message)).inRoot(new ToastMatcher()) .check(matches(not(isDisplayed())));
Test id the Toast contains specific Text Message Toast 包含特定文本消息的测试 ID
onView(withText(R.string.message)).inRoot(new ToastMatcher()) .check(matches(withText("Invalid Name"));
I copied this answer from my blog - http://qaautomated.blogspot.in/2016/01/how-to-test-toast-message-using-espresso.html我从我的博客中复制了这个答案 - http://qaautomated.blogspot.in/2016/01/how-to-test-toast-message-using-espresso.html
This works这有效
boolean exceptionCaptured = false;
try {
onView(withText(R.string.error_invalid_login))
.inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView()))))
.check(doesNotExist());
}catch (NoMatchingRootException e){
exceptionCaptured = true;
}finally {
assertTrue(exceptionCaptured);
}
Seems that such simple check is impossible with espresso if you have not only toast but a PopupWindow
, for example.例如,如果您不仅有吐司而且有一个
PopupWindow
,那么对于 espresso 来说,这种简单的检查似乎是不可能的。
For this case is suggest just to give up with espresso here and use UiAutomator
for this assertion对于这种情况,建议在这里放弃浓缩咖啡并使用
UiAutomator
进行此断言
val device: UiDevice
get() = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
fun assertPopupIsNotDisplayed() {
device.waitForIdle()
assertFalse(device.hasObject(By.text(yourText))))
}
fun assertPopupIsDisplayed() {
device.waitForIdle()
assertTrue(device.hasObject(By.text(yourText))))
}
I know its late but may be this will help somebody else.我知道为时已晚,但可能这会对其他人有所帮助。
onView(withText("Test")).inRoot(withDecorView(not(mActivityRule.getActivity().getWindow().getDecorView())))
.check(doesNotExist());
Like @anuja jain's answer but if you get the NoMatchingRootException
you can comment out the if ((type == WindowManager.LayoutParams.TYPE_TOAST))
check and add the return true;
就像@anuja jain 的回答一样,但是如果您得到
NoMatchingRootException
您可以注释掉if ((type == WindowManager.LayoutParams.TYPE_TOAST))
检查并添加return true;
line to the inner if block.行到内部 if 块。
Try with below solution尝试使用以下解决方案
onView(withId(android.R.id.message))
.inRoot(withDecorView(not(is(mRule.getActivity().getWindow().getDecorView()))))
.check(matches(withText("Some message")));
你可以在这里查看源代码并创建你自己的视图匹配器,它的作用正好相反。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.