最近我遇到了一个Toast
的JUnit Testing
的问题。
在我的LoginActivity
类中,我有一个Button
,它调用以下代码:
Toast.makeText(LoginActivity.this, "toast text", Toast.LENGTH_SHORT).show();
这是一个LoginActivityTest
类
package com.android_pokladna.LoginActivity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.test.core.app.ActivityScenario;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
import androidx.test.rule.ActivityTestRule;
import com.android_pokladna.Model.Login.LoginRequest;
import com.android_pokladna.Model.Login.LoginResponse;
import com.android_pokladna.Other.TokenSaver;
import com.android_pokladna.R;
import com.android_pokladna.ShopActivity.ShopActivity;
import com.android_pokladna.api.ApiClientandService.ApiCallback;
import com.android_pokladna.api.ApiClientandService.ApiClient;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.RootMatchers.isFocusable;
import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup;
import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*;
public class LoginActivityTest {
@Rule
public ActivityTestRule<LoginActivity> activityTestRule = new ActivityTestRule(LoginActivity.class);
private LoginActivity loginActivity = null;
public static ViewAction waitFor(final long millis) {
return new ViewAction() {
@Override
public Matcher<View> getConstraints() {
return isRoot();
}
@Override
public String getDescription() {
return "Wait for " + millis + " milliseconds.";
}
@Override
public void perform(UiController uiController, final View view) {
uiController.loopMainThreadForAtLeast(millis);
}
};
}
@Before
public void setUp() throws Exception {
loginActivity = activityTestRule.getActivity();
//clears all system dialogs
loginActivity.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
@Test
public void testDialogButtonClick() throws Throwable {
onView(withId(R.id.activityLoginButtonEnter)).perform(click());
onView(withId(R.id.activityLoginDialogButton)).perform(click());
onView(withText("TEXT")).inRoot(new ToastMatcher())
.check(matches(withText("TEXT")));
}
@After
public void tearDown() throws Exception {
loginActivity = null;
}
}
问题在于这部分代码:
onView(withText("toast text")).inRoot(new ToastMatcher())
.check(matches(withText("toast text")));
会引发error
:
androidx.test.espresso.NoMatchingRootException: Matcher 'is toast' did not match any of the following roots: [Root{application-window-token=android.view.ViewRootImpl$W@a78c87f, window-token=android.view.ViewRootImpl$W@a78c87f, has-window-focus=true, layout-params-type=2, layout-params-string={(0,0)(wrapxwrap) gr=CENTER sim={adjust=pan} ty=APPLICATION fmt=TRANSPARENT wanim=0x10302ff
fl=DIM_BEHIND SPLIT_TOUCH HARDWARE_ACCELERATED
fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=1144, height=1300, has-focus=false, 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, layout-params={(0,0)(wrapxwrap) gr=CENTER sim={adjust=pan} ty=APPLICATION fmt=TRANSPARENT wanim=0x10302ff
fl=DIM_BEHIND SPLIT_TOUCH HARDWARE_ACCELERATED
fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}, Root{application-window-token=android.view.ViewRootImpl$W@3be404c, window-token=android.view.ViewRootImpl$W@3be404c, has-window-focus=false, layout-params-type=1, layout-params-string={(0,0)(fillxfill) sim={adjust=pan} ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND FIT_INSETS_CONTROLLED
fitSides=}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=2560, height=1600, has-focus=false, has-focusable=true, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) sim={adjust=pan} ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND FIT_INSETS_CONTROLLED
fitSides=}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3}}]
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:1736)
at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:12)
at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:7)
at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:8)
at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:12)
at com.android_pokladna.LoginActivity.LoginActivityTest.testDialogButtonClick(LoginActivityTest.java:116)
Tests ran to completion.
在test
类中,我使用了如下所示的ToastMatcher类:
package com.android_pokladna.LoginActivity;
import android.os.IBinder;
import android.view.WindowManager;
import androidx.test.espresso.Root;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
public class ToastMatcher extends TypeSafeMatcher<Root> {
/*
Author: http://www.qaautomated.com/2016/01/how-to-test-toast-message-using-espresso.html
*/
@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) {
return true;
}
}
return false;
}
}
我已经看到很多人都有类似的问题。我是根据一个测试成功的视频来做的:https://www.youtube.com/watch?v=L037q8MGkGA&ab_channel=CodingWithMitch
他的视频真的很有帮助,但我不明白我得到的错误。测试需要一段时间才能完成,当toast
得到测试。它已经走了,也许这就是为什么它抛出一个错误。
如果有人能帮助我,我将不胜感激。谢谢你的帮助!
1条答案
按热度按时间dwthyt8l1#
这里我也遇到了与inRoot相关的相同错误,因此我使用了另一个解决方案来Assert吐司消息,用UIAutomator和assertTrue替换了inRoot和ToastMatcher类: