Android 에스프레소에서 토스트 메시지 확인
안드로이드 에스프레소에서 토스트 메시지의 모양을 테스트하는 방법을 아는 사람이 있습니까? robotium에서는 쉽고 사용했지만 에스프레소 작업을 시작했지만 정확한 명령을 얻지 못했습니다.
이 약간 긴 문장이 저에게 효과적입니다.
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
....
onView(withText(R.string.TOAST_STRING)).inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView())))).check(matches(isDisplayed()));
받아 들여진 대답은 좋은 대답이지만 저에게는 효과가 없었습니다. 그래서 조금 검색해서이 블로그 기사를 찾았습니다 . 이를 통해 수행 방법에 대한 아이디어를 얻었으며 위의 솔루션을 업데이트했습니다.
먼저 ToastMatcher를 구현했습니다.
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) {
// 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;
}
}
그런 다음 다음과 같은 검사 방법을 구현했습니다.
public void isToastMessageDisplayed(int textId) {
onView(withText(textId)).inRoot(MobileViewMatchers.isToast()).check(matches(isDisplayed()));
}
MobileViewMatchers는 매처에 액세스하기위한 컨테이너입니다. 거기에 정적 메서드를 정의했습니다 isToast()
.
public static Matcher<Root> isToast() {
return new ToastMatcher();
}
이것은 나에게 매력처럼 작동합니다.
먼저 가져와야합니다.
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
수업 안에는 다음과 같은 규칙이있을 것입니다.
@Rule
public ActivityTestRule<MyNameActivity> activityTestRule =
new ActivityTestRule<>(MyNameActivity.class);
테스트 내용 :
MyNameActivity activity = activityTestRule.getActivity();
onView(withText(R.string.toast_text)).
inRoot(withDecorView(not(is(activity.getWindow().getDecorView())))).
check(matches(isDisplayed()));
이것은 나를 위해 일했으며 사용하기가 매우 쉬웠습니다.
질문에 허용 된 답변이 있지만-어떤 BTW가 저에게 적합하지 않은지-Thomas R.의 답변에서 파생 된 Kotlin에 솔루션을 추가하고 싶습니다.
package somepkg
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.Root
import android.support.test.espresso.matcher.ViewMatchers.withText
import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
import android.view.WindowManager.LayoutParams.TYPE_TOAST
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.TypeSafeMatcher
/**
* This class allows to match Toast messages in tests with Espresso.
*
* Idea taken from: https://stackoverflow.com/a/33387980
*
* Usage in test class:
*
* import somepkg.ToastMatcher.Companion.onToast
*
* // To assert a toast does *not* pop up:
* onToast("text").check(doesNotExist())
* onToast(textId).check(doesNotExist())
*
* // To assert a toast does pop up:
* onToast("text").check(matches(isDisplayed()))
* onToast(textId).check(matches(isDisplayed()))
*/
class ToastMatcher(private val maxFailures: Int = DEFAULT_MAX_FAILURES) : TypeSafeMatcher<Root>() {
/** Restrict number of false results from matchesSafely to avoid endless loop */
private var failures = 0
override fun describeTo(description: Description) {
description.appendText("is toast")
}
public override fun matchesSafely(root: Root): Boolean {
val type = root.windowLayoutParams.get().type
@Suppress("DEPRECATION") // TYPE_TOAST is deprecated in favor of TYPE_APPLICATION_OVERLAY
if (type == TYPE_TOAST || type == TYPE_APPLICATION_OVERLAY) {
val windowToken = root.decorView.windowToken
val appToken = root.decorView.applicationWindowToken
if (windowToken === appToken) {
// 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
}
}
// Method is called again if false is returned which is useful because a toast may take some time to pop up. But for
// obvious reasons an infinite wait isn't of help. So false is only returned as often as maxFailures specifies.
return (++failures >= maxFailures)
}
companion object {
/** Default for maximum number of retries to wait for the toast to pop up */
private const val DEFAULT_MAX_FAILURES = 5
fun onToast(text: String, maxRetries: Int = DEFAULT_MAX_FAILURES) = onView(withText(text)).inRoot(isToast(maxRetries))!!
fun onToast(textId: Int, maxRetries: Int = DEFAULT_MAX_FAILURES) = onView(withText(textId)).inRoot(isToast(maxRetries))!!
fun isToast(maxRetries: Int = DEFAULT_MAX_FAILURES): Matcher<Root> {
return ToastMatcher(maxRetries)
}
}
}
나는 이것이 나중에 독자들에게 도움이되기를 바랍니다. 사용법은 주석에 설명되어 있습니다.
먼저 테스트 케이스에서 사용할 수있는 cutom Toast Matcher를 만듭니다.
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;
}
}
1. 토스트 메시지가 표시되는지 테스트
onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
.check(matches(isDisplayed()));
2. 토스트 메시지가 표시되지 않는지 테스트
onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
.check(matches(not(isDisplayed())));
3. 토스트에 특정 텍스트 메시지가 포함 된 테스트 ID
onView(withText(R.string.mssage)).inRoot(new ToastMatcher())
.check(matches(withText("Invalid Name"));
감사합니다, Anuja
참고-이 답변은 This POST 에서 가져온 것입니다 .
토스트 메시지에 대해 먼저 규칙을 정의한다고 말하고 싶습니다.
@Rule
public ActivityTestRule<AuthActivity> activityTestRule =
new ActivityTestRule<>(AuthActivity.class);
그런 다음 원하는 토스트 메시지 텍스트를 인용문 사이에 입력하십시오. 예를 들어 "잘못된 이메일 주소"를 사용했습니다.
onView(withText("Invalid email address"))
.inRoot(withDecorView(not(activityTestRule.getActivity().getWindow().getDecorView())))
.check(matches(isDisplayed()));
Jetpack 의 최신 Android 테스트 도구 를 사용하는 경우 ActivityTestRule이 더 이상 사용되지 않으며 ActivityScenario 또는 ActivityScenarioRule (첫 번째 포함)을 사용해야합니다.
전제 조건. decorView 변수를 만들고 테스트 전에 할당하십시오.
@Rule
public ActivityScenarioRule<FeedActivity> activityScenarioRule = new ActivityScenarioRule<>(FeedActivity.class);
private View decorView;
@Before
public void setUp() {
activityScenarioRule.getScenario().onActivity(new ActivityScenario.ActivityAction<FeedActivity>() {
@Override
public void perform(FeedActivityactivity) {
decorView = activity.getWindow().getDecorView();
}
});
}
자체 테스트
@Test
public void given_when_thenShouldShowToast() {
String expectedWarning = getApplicationContext().getString(R.string.error_empty_list);
onView(withId(R.id.button))
.perform(click());
onView(withText(expectedWarning))
.inRoot(withDecorView(not(decorView)))// Here we use decorView
.check(matches(isDisplayed()));
}
getApplicationContext () 는 다음에서 가져올 수 있습니다.androidx.test.core.app.ApplicationProvider.getApplicationContext;
내 사용자 지정 토스트 매처를 작성합니다.
import android.view.WindowManager
import androidx.test.espresso.Root
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
class ToastMatcher : TypeSafeMatcher<Root>() {
override fun describeTo(description: Description) {
description.appendText("is toast")
}
override fun matchesSafely(root: Root): Boolean {
val type = root.getWindowLayoutParams().get().type
if (type == WindowManager.LayoutParams.TYPE_TOAST) {
val windowToken = root.getDecorView().getWindowToken()
val appToken = root.getDecorView().getApplicationWindowToken()
if (windowToken === appToken) {
return true
}
}
return false
}
}
다음과 같이 사용하십시오.
onView(withText(R.string.please_input_all_fields)).inRoot(ToastMatcher()).check(matches(isDisplayed()))
나는 이것에 대해 꽤 생소하지만 내 모든 작업 (스 와이프, 클릭 등)과 확인 (텍스트보기에서 콘텐츠 확인 등)이 포함 된 기본 클래스 'BaseTest'를 만들었습니다.
protected fun verifyToastMessageWithText(text: String, activityTestRule: ActivityTestRule<*>) {
onView(withText(text)).inRoot(withDecorView(not(activityTestRule.activity.window.decorView))).check(matches(isDisplayed()))
}
protected fun verifyToastMessageWithStringResource(id: Int, activityTestRule: ActivityTestRule<*>) {
onView(withText(id)).inRoot(withDecorView(not(activityTestRule.activity.window.decorView))).check(matches(isDisplayed()))
}
The way Toasts are implemented makes it possible to detect a toast has been displayed. However there is no way to see if a Toast has been requested, thru a call to show()) or to block between the period of time between show() and when the toast has become visible. This is opens up unresolvable timing issues (that you can only address thru sleep & hope).
If you really really want to verify this, here's a not-so-pretty alternative using Mockito and a test spy:
public interface Toaster {
public void showToast(Toast t);
private static class RealToaster {
@Override
public void showToast(Toast t) {
t.show();
}
public static Toaster makeToaster() {
return new RealToaster();
}
}
Then in your test
public void testMyThing() {
Toaster spyToaster = Mockito.spy(Toaster.makeToaster());
getActivity().setToaster(spyToaster);
onView(withId(R.button)).perform(click());
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
// must do this on the main thread because the matcher will be interrogating a view...
Mockito.verify(spyToaster).showToast(allOf(withDuration(Toast.LENGTH_SHORT), withView(withText("hello world"));
});
}
// create a matcher that calls getDuration() on the toast object
Matcher<Toast> withDuration(int)
// create a matcher that calls getView() and applies the given view matcher
Matcher<Toast> withView(Matcher<View> viewMatcher)
another answer regarding this
if(someToast == null)
someToast = Toast.makeText(this, "sdfdsf", Toast.LENGTH_LONG);
boolean isShown = someToast.getView().isShown();
참고URL : https://stackoverflow.com/questions/28390574/checking-toast-message-in-android-espresso
'Programing' 카테고리의 다른 글
SQL Server에서 하위 쿼리를 사용하여 쿼리 업데이트 (0) | 2020.11.23 |
---|---|
Xvfb 실패 시작 오류 (0) | 2020.11.23 |
jQuery를 사용하여 div가 스크롤을 부드럽게 따르도록 만드는 방법은 무엇입니까? (0) | 2020.11.23 |
보안 페이지에서 모든 안전하지 않은 콘텐츠 찾기 (0) | 2020.11.23 |
한 번에 여러 문자열 바꾸기 (0) | 2020.11.23 |