program story

에스프레소 : Thread.sleep ();

inputbox 2020. 9. 7. 08:06
반응형

에스프레소 : Thread.sleep ();


Espresso는에 대한 필요가 없다고 주장 Thread.sleep();하지만 코드를 포함하지 않으면 코드가 작동하지 않습니다. IP에 연결 중입니다. 연결하는 동안 진행률 대화 상자가 표시됩니다. 나는 필요 sleep대화 상자가 기각 때까지 기다릴. 이것은 내가 사용하는 내 테스트 스 니펫입니다.

    IP.enterIP(); // fills out an IP dialog (this is done with espresso)

    //progress dialog is now shown
    Thread.sleep(1500);

    onView(withId(R.id.button).perform(click());

이 코드를 시도 으로 하고 없이Thread.sleep(); 하지만 말한다 R.id.Button존재하지 않습니다. 작동하도록 할 수있는 유일한 방법은 수면입니다.

또한, 나는 교체 시도 Thread.sleep();와 같은 것들로 getInstrumentation().waitForIdleSync();여전히 행운.

이것이 유일한 방법입니까? 아니면 내가 뭔가를 놓치고 있습니까?

미리 감사드립니다.


내 마음에 올바른 접근 방식은 다음과 같습니다.

/** Perform action of waiting for a specific view id. */
public static ViewAction waitId(final int viewId, final long millis) {
    return new ViewAction() {
        @Override
        public Matcher<View> getConstraints() {
            return isRoot();
        }

        @Override
        public String getDescription() {
            return "wait for a specific view with id <" + viewId + "> during " + millis + " millis.";
        }

        @Override
        public void perform(final UiController uiController, final View view) {
            uiController.loopMainThreadUntilIdle();
            final long startTime = System.currentTimeMillis();
            final long endTime = startTime + millis;
            final Matcher<View> viewMatcher = withId(viewId);

            do {
                for (View child : TreeIterables.breadthFirstViewTraversal(view)) {
                    // found view with required ID
                    if (viewMatcher.matches(child)) {
                        return;
                    }
                }

                uiController.loopMainThreadForAtLeast(50);
            }
            while (System.currentTimeMillis() < endTime);

            // timeout happens
            throw new PerformException.Builder()
                    .withActionDescription(this.getDescription())
                    .withViewDescription(HumanReadables.describe(view))
                    .withCause(new TimeoutException())
                    .build();
        }
    };
}

그리고 사용 패턴은 다음과 같습니다.

// wait during 15 seconds for a view
onView(isRoot()).perform(waitId(R.id.dialogEditor, TimeUnit.SECONDS.toMillis(15)));

그의 멋진 답변에 대해 AlexK에게 감사드립니다. 코드에서 약간의 지연이 필요한 경우가 있습니다. 반드시 서버 응답을 기다리는 것은 아니지만 애니메이션이 완료되기를 기다리고있을 수 있습니다. 개인적으로 Espresso idolingResources에 문제가 있습니다 (간단한 작업을 위해 여러 줄의 코드를 작성하고 있다고 생각합니다). 그래서 AlexK가 수행하는 방식을 다음 코드로 변경했습니다.

/**
 * Perform action of waiting for a specific time.
 */
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);
        }
    };
}

따라서 Delay쉽게 액세스 할 수 있도록 클래스를 만들고이 메서드를 넣을 수 있습니다. 테스트 클래스에서 같은 방식으로 사용할 수 있습니다.onView(isRoot()).perform(waitFor(5000));


서버 응답을 기다리고 응답을 기반으로 요소의 가시성을 변경하는 유사한 문제에 대한 답변을 찾을 때이 스레드를 우연히 발견했습니다.

위의 솔루션이 확실히 도움이되었지만 결국 chiuki에서이 훌륭한 예제를 찾았고 이제 앱 유휴 기간 동안 작업이 발생하기를 기다릴 때마다이 접근 방식을 사용합니다.

내 유틸리티 클래스 ElapsedTimeIdlingResource ()추가 했으며 이제이를 Espresso-proper 대안으로 효과적으로 사용할 수 있으며 이제 사용이 멋지고 깨끗합니다.

// Make sure Espresso does not time out
IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);

// Now we wait
IdlingResource idlingResource = new ElapsedTimeIdlingResource(waitingTime);
Espresso.registerIdlingResources(idlingResource);

// Stop and verify
onView(withId(R.id.toggle_button))
    .check(matches(withText(R.string.stop)))
    .perform(click());
onView(withId(R.id.result))
    .check(matches(withText(success ? R.string.success: R.string.failure)));

// Clean up
Espresso.unregisterIdlingResources(idlingResource);

이 줄을 추가하는 것이 더 쉽습니다.

SystemClock.sleep(1500);

반환하기 전에 주어진 밀리 초 (uptimeMillis)를 기다립니다. sleep (long)과 유사하지만 InterruptedException을 발생시키지 않습니다. interrupt () 이벤트는 다음 인터럽트 가능한 작업까지 연기됩니다. 최소한 지정된 시간 (밀리 초)이 경과 할 때까지 반환되지 않습니다.


Barista 방법을 사용할 수 있습니다.

BaristaSleepActions.sleep(2000);

BaristaSleepActions.sleep(2, SECONDS);

Barista는 수락 된 답변에 필요한 모든 코드를 추가하지 않도록 Espresso를 래핑하는 라이브러리입니다. 그리고 여기에 링크가 있습니다! https://github.com/SchibstedSpain/Barista


저는 코딩과 Espresso를 처음 사용하기 때문에 유휴 상태를 사용하는 것이 좋고 합리적인 해결책이라는 것을 알고 있지만 아직 그렇게 할만큼 지능적이지는 않습니다.

지식이 더 많아 질 때까지 어떻게 든 실행하려면 테스트가 필요하므로 지금은 요소를 찾으려고 여러 번 시도하고 발견하면 중지하고 그렇지 않으면 잠시 잠자고 시작하는이 더러운 솔루션을 사용하고 있습니다. 최대 시도 횟수에 도달 할 때까지 다시 시도합니다 (지금까지 가장 높은 시도 횟수는 약 150 회입니다).

private static boolean waitForElementUntilDisplayed(ViewInteraction element) {
    int i = 0;
    while (i++ < ATTEMPTS) {
        try {
            element.check(matches(isDisplayed()));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            try {
                Thread.sleep(WAITING_TIME);
            } catch (Exception e1) {
                e.printStackTrace();
            }
        }
    }
    return false;
}

ID, 텍스트, 부모 등으로 요소를 찾는 모든 방법에서 이것을 사용하고 있습니다.

static ViewInteraction findById(int itemId) {
    ViewInteraction element = onView(withId(itemId));
    waitForElementUntilDisplayed(element);
    return element;
}

Espresso는 테스트에서 sleep () 호출을 피하기 위해 만들어졌습니다. 테스트는 테스트 된 활동의 책임 인 IP를 입력하는 대화 상자를 열지 않아야합니다.

반면에 UI 테스트는 다음을 수행해야합니다.

  • IP 대화 상자가 나타날 때까지 기다립니다.
  • IP 주소를 입력하고 Enter를 클릭하십시오.
  • 버튼이 나타날 때까지 기다렸다가 클릭하십시오.

테스트는 다음과 같아야합니다.

// type the IP and press OK
onView (withId (R.id.dialog_ip_edit_text))
  .check (matches(isDisplayed()))
  .perform (typeText("IP-TO-BE-TYPED"));

onView (withText (R.string.dialog_ok_button_title))
  .check (matches(isDisplayed()))
  .perform (click());

// now, wait for the button and click it
onView (withId (R.id.button))
  .check (matches(isDisplayed()))
  .perform (click());

Espresso는 테스트를 실행하기 전에 UI 스레드와 AsyncTask 풀에서 발생하는 모든 작업이 완료 될 때까지 기다립니다.

테스트는 애플리케이션의 책임을 수행해서는 안된다는 것을 기억하십시오. 이것은 "잘 알고있는 사용자"처럼 행동해야합니다. 클릭하고 화면에 무언가가 표시되는지 확인하지만 실제로는 구성 요소의 ID를 알고있는 사용자


Espresso Idling Resource를 사용해야합니다.이 CodeLab 에서 제안합니다.

유휴 리소스는 결과가 UI 테스트의 후속 작업에 영향을 미치는 비동기 작업을 나타냅니다. Espresso에 유휴 리소스를 등록하면 앱을 테스트 할 때 이러한 비동기 작업을보다 안정적으로 검증 할 수 있습니다.

발표자의 비동기 호출 예

@Override
public void loadNotes(boolean forceUpdate) {
   mNotesView.setProgressIndicator(true);
   if (forceUpdate) {
       mNotesRepository.refreshData();
   }

   // The network request might be handled in a different thread so make sure Espresso knows
   // that the app is busy until the response is handled.
   EspressoIdlingResource.increment(); // App is busy until further notice

   mNotesRepository.getNotes(new NotesRepository.LoadNotesCallback() {
       @Override
       public void onNotesLoaded(List<Note> notes) {
           EspressoIdlingResource.decrement(); // Set app as idle.
           mNotesView.setProgressIndicator(false);
           mNotesView.showNotes(notes);
       }
   });
}

의존성

androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
    implementation 'androidx.test.espresso:espresso-idling-resource:3.1.1'

androidx의 경우

androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    implementation 'com.android.support.test.espresso:espresso-idling-resource:3.0.2'

공식 저장소 : https://github.com/googlecodelabs/android-testing

IdlingResource 예 : https://github.com/googlesamples/android-testing/tree/master/ui/espresso/IdlingResourceSample


이것은 이 답변 과 유사 하지만 시도 대신 시간 초과를 사용하며 다른 ViewInteractions와 연결할 수 있습니다.

/**
 * Wait for view to be visible
 */
fun ViewInteraction.waitUntilVisible(timeout: Long): ViewInteraction {
    val startTime = System.currentTimeMillis()
    val endTime = startTime + timeout

    do {
        try {
            check(matches(isDisplayed()))
            return this
        } catch (e: NoMatchingViewException) {
            Thread.sleep(50)
        }
    } while (System.currentTimeMillis() < endTime)

    throw TimeoutException()
}

용법:

onView(withId(R.id.whatever))
    .waitUntilVisible(5000)
    .perform(click())

Idling Resources를 사용하는 것이 가장 좋다고 생각하지만 ( https://google.github.io/android-testing-support-library/docs/espresso/idling-resource/ ) 아마도 이것을 대체 수단으로 사용할 수 있습니다.

/**
 * Contains view interactions, view actions and view assertions which allow to set a timeout
 * for finding a view and performing an action/view assertion on it.
 * To be used instead of {@link Espresso}'s methods.
 * 
 * @author Piotr Zawadzki
 */
public class TimeoutEspresso {

    private static final int SLEEP_IN_A_LOOP_TIME = 50;

    private static final long DEFAULT_TIMEOUT_IN_MILLIS = 10 * 1000L;

    /**
     * Use instead of {@link Espresso#onView(Matcher)}
     * @param timeoutInMillis timeout after which an error is thrown
     * @param viewMatcher view matcher to check for view
     * @return view interaction
     */
    public static TimedViewInteraction onViewWithTimeout(long timeoutInMillis, @NonNull final Matcher<View> viewMatcher) {

        final long startTime = System.currentTimeMillis();
        final long endTime = startTime + timeoutInMillis;

        do {
            try {
                return new TimedViewInteraction(Espresso.onView(viewMatcher));
            } catch (NoMatchingViewException ex) {
                //ignore
            }

            SystemClock.sleep(SLEEP_IN_A_LOOP_TIME);
        }
        while (System.currentTimeMillis() < endTime);

        // timeout happens
        throw new PerformException.Builder()
                .withCause(new TimeoutException("Timeout occurred when trying to find: " + viewMatcher.toString()))
                .build();
    }

    /**
     * Use instead of {@link Espresso#onView(Matcher)}.
     * Same as {@link #onViewWithTimeout(long, Matcher)} but with the default timeout {@link #DEFAULT_TIMEOUT_IN_MILLIS}.
     * @param viewMatcher view matcher to check for view
     * @return view interaction
     */
    public static TimedViewInteraction onViewWithTimeout(@NonNull final Matcher<View> viewMatcher) {
        return onViewWithTimeout(DEFAULT_TIMEOUT_IN_MILLIS, viewMatcher);
    }

    /**
     * A wrapper around {@link ViewInteraction} which allows to set timeouts for view actions and assertions.
     */
    public static class TimedViewInteraction {

        private ViewInteraction wrappedViewInteraction;

        public TimedViewInteraction(ViewInteraction wrappedViewInteraction) {
            this.wrappedViewInteraction = wrappedViewInteraction;
        }

        /**
         * @see ViewInteraction#perform(ViewAction...)
         */
        public TimedViewInteraction perform(final ViewAction... viewActions) {
            wrappedViewInteraction.perform(viewActions);
            return this;
        }

        /**
         * {@link ViewInteraction#perform(ViewAction...)} with a timeout of {@link #DEFAULT_TIMEOUT_IN_MILLIS}.
         * @see ViewInteraction#perform(ViewAction...)
         */
        public TimedViewInteraction performWithTimeout(final ViewAction... viewActions) {
            return performWithTimeout(DEFAULT_TIMEOUT_IN_MILLIS, viewActions);
        }

        /**
         * {@link ViewInteraction#perform(ViewAction...)} with a timeout.
         * @see ViewInteraction#perform(ViewAction...)
         */
        public TimedViewInteraction performWithTimeout(long timeoutInMillis, final ViewAction... viewActions) {
            final long startTime = System.currentTimeMillis();
            final long endTime = startTime + timeoutInMillis;

            do {
                try {
                    return perform(viewActions);
                } catch (RuntimeException ex) {
                    //ignore
                }

                SystemClock.sleep(SLEEP_IN_A_LOOP_TIME);
            }
            while (System.currentTimeMillis() < endTime);

            // timeout happens
            throw new PerformException.Builder()
                    .withCause(new TimeoutException("Timeout occurred when trying to perform view actions: " + viewActions))
                    .build();
        }

        /**
         * @see ViewInteraction#withFailureHandler(FailureHandler)
         */
        public TimedViewInteraction withFailureHandler(FailureHandler failureHandler) {
            wrappedViewInteraction.withFailureHandler(failureHandler);
            return this;
        }

        /**
         * @see ViewInteraction#inRoot(Matcher)
         */
        public TimedViewInteraction inRoot(Matcher<Root> rootMatcher) {
            wrappedViewInteraction.inRoot(rootMatcher);
            return this;
        }

        /**
         * @see ViewInteraction#check(ViewAssertion)
         */
        public TimedViewInteraction check(final ViewAssertion viewAssert) {
            wrappedViewInteraction.check(viewAssert);
            return this;
        }

        /**
         * {@link ViewInteraction#check(ViewAssertion)} with a timeout of {@link #DEFAULT_TIMEOUT_IN_MILLIS}.
         * @see ViewInteraction#check(ViewAssertion)
         */
        public TimedViewInteraction checkWithTimeout(final ViewAssertion viewAssert) {
            return checkWithTimeout(DEFAULT_TIMEOUT_IN_MILLIS, viewAssert);
        }

        /**
         * {@link ViewInteraction#check(ViewAssertion)} with a timeout.
         * @see ViewInteraction#check(ViewAssertion)
         */
        public TimedViewInteraction checkWithTimeout(long timeoutInMillis, final ViewAssertion viewAssert) {
            final long startTime = System.currentTimeMillis();
            final long endTime = startTime + timeoutInMillis;

            do {
                try {
                    return check(viewAssert);
                } catch (RuntimeException ex) {
                    //ignore
                }

                SystemClock.sleep(SLEEP_IN_A_LOOP_TIME);
            }
            while (System.currentTimeMillis() < endTime);

            // timeout happens
            throw new PerformException.Builder()
                    .withCause(new TimeoutException("Timeout occurred when trying to check: " + viewAssert.toString()))
                    .build();
        }
    }
}

그런 다음 코드에서 다음과 같이 호출하십시오.

onViewWithTimeout(withId(R.id.button).perform(click());

대신에

onView(withId(R.id.button).perform(click());

또한 뷰 작업 및 뷰 어설 션에 대한 시간 제한을 추가 할 수 있습니다.


내 유틸리티는 오류없이 통과하거나 시간 초과 후 throw 가능할 때까지 실행 가능 또는 호출 가능 실행을 반복합니다. 에스프레소 테스트에 완벽하게 작동합니다!

마지막 뷰 상호 작용 (버튼 클릭)이 일부 백그라운드 스레드 (네트워크, 데이터베이스 등)를 활성화한다고 가정합니다. 결과적으로 새 화면이 나타나야하며 다음 단계에서 확인하고 싶지만 새 화면이 언제 테스트 될 준비가되었는지 알 수 없습니다.

권장되는 접근 방식은 앱이 스레드 상태에 대한 메시지를 테스트에 보내도록하는 것입니다. 때때로 우리는 OkHttp3IdlingResource와 같은 내장 메커니즘을 사용할 수 있습니다. 다른 경우에는 테스트 지원만을 위해 앱 소스의 다른 위치에 코드 조각을 삽입해야합니다 (앱 로직을 알고 있어야합니다!). 또한 모든 애니메이션을 꺼야합니다 (UI의 일부 임에도 불구하고).

다른 접근 방식은 대기 중입니다 (예 : SystemClock.sleep (10000)). 그러나 우리는 얼마나 오래 기다려야할지 모르고 긴 지연조차도 성공을 보장 할 수 없습니다. 반면에 테스트는 오래 지속됩니다.

내 접근 방식은 상호 작용을 볼 시간 조건을 추가하는 것입니다. 예를 들어 10000mc (시간 초과) 동안 새 화면이 표시되는지 테스트합니다. 그러나 우리는 원하는만큼 빨리 (예 : 100ms마다) 기다리지 않고 확인합니다. 물론 테스트 스레드를 이러한 방식으로 차단하지만 일반적으로 이러한 경우에 필요한 것입니다.

Usage:

long timeout=10000;
long matchDelay=100; //(check every 100 ms)
EspressoExecutor myExecutor = new EspressoExecutor<ViewInteraction>(timeout, matchDelay);

ViewInteraction loginButton = onView(withId(R.id.login_btn));
loginButton.perform(click());

myExecutor.callForResult(()->onView(allOf(withId(R.id.title),isDisplayed())));

이것은 내 수업 소스입니다.

/**
 * Created by alexshr on 02.05.2017.
 */

package com.skb.goodsapp;

import android.os.SystemClock;
import android.util.Log;

import java.util.Date;
import java.util.concurrent.Callable;

/**
 * The utility repeats runnable or callable executing until it pass without errors or throws throwable after timeout.
 * It works perfectly for Espresso tests.
 * <p>
 * Suppose the last view interaction (button click) activates some background threads (network, database etc.).
 * As the result new screen should appear and we want to check it in our next step,
 * but we don't know when new screen will be ready to be tested.
 * <p>
 * Recommended approach is to force your app to send messages about threads states to your test.
 * Sometimes we can use built-in mechanisms like OkHttp3IdlingResource.
 * In other cases you should insert code pieces in different places of your app sources (you should known app logic!) for testing support only.
 * Moreover, we should turn off all your animations (although it's the part on ui).
 * <p>
 * The other approach is waiting, e.g. SystemClock.sleep(10000). But we don't known how long to wait and even long delays can't guarantee success.
 * On the other hand your test will last long.
 * <p>
 * My approach is to add time condition to view interaction. E.g. we test that new screen should appear during 10000 mc (timeout).
 * But we don't wait and check new screen as quickly as it appears.
 * Of course, we block test thread such way, but usually it's just what we need in such cases.
 * <p>
 * Usage:
 * <p>
 * long timeout=10000;
 * long matchDelay=100; //(check every 100 ms)
 * EspressoExecutor myExecutor = new EspressoExecutor<ViewInteraction>(timeout, matchDelay);
 * <p>
 * ViewInteraction loginButton = onView(withId(R.id.login_btn));
 * loginButton.perform(click());
 * <p>
 * myExecutor.callForResult(()->onView(allOf(withId(R.id.title),isDisplayed())));
 */
public class EspressoExecutor<T> {

    private static String LOG = EspressoExecutor.class.getSimpleName();

    public static long REPEAT_DELAY_DEFAULT = 100;
    public static long BEFORE_DELAY_DEFAULT = 0;

    private long mRepeatDelay;//delay between attempts
    private long mBeforeDelay;//to start attempts after this initial delay only

    private long mTimeout;//timeout for view interaction

    private T mResult;

    /**
     * @param timeout     timeout for view interaction
     * @param repeatDelay - delay between executing attempts
     * @param beforeDelay - to start executing attempts after this delay only
     */

    public EspressoExecutor(long timeout, long repeatDelay, long beforeDelay) {
        mRepeatDelay = repeatDelay;
        mBeforeDelay = beforeDelay;
        mTimeout = timeout;
        Log.d(LOG, "created timeout=" + timeout + " repeatDelay=" + repeatDelay + " beforeDelay=" + beforeDelay);
    }

    public EspressoExecutor(long timeout, long repeatDelay) {
        this(timeout, repeatDelay, BEFORE_DELAY_DEFAULT);
    }

    public EspressoExecutor(long timeout) {
        this(timeout, REPEAT_DELAY_DEFAULT);
    }


    /**
     * call with result
     *
     * @param callable
     * @return callable result
     * or throws RuntimeException (test failure)
     */
    public T call(Callable<T> callable) {
        call(callable, null);
        return mResult;
    }

    /**
     * call without result
     *
     * @param runnable
     * @return void
     * or throws RuntimeException (test failure)
     */
    public void call(Runnable runnable) {
        call(runnable, null);
    }

    private void call(Object obj, Long initialTime) {
        try {
            if (initialTime == null) {
                initialTime = new Date().getTime();
                Log.d(LOG, "sleep delay= " + mBeforeDelay);
                SystemClock.sleep(mBeforeDelay);
            }

            if (obj instanceof Callable) {
                Log.d(LOG, "call callable");
                mResult = ((Callable<T>) obj).call();
            } else {
                Log.d(LOG, "call runnable");
                ((Runnable) obj).run();
            }
        } catch (Throwable e) {
            long remain = new Date().getTime() - initialTime;
            Log.d(LOG, "remain time= " + remain);
            if (remain > mTimeout) {
                throw new RuntimeException(e);
            } else {
                Log.d(LOG, "sleep delay= " + mRepeatDelay);
                SystemClock.sleep(mRepeatDelay);
                call(obj, initialTime);
            }
        }
    }
}

https://gist.github.com/alexshr/ca90212e49e74eb201fbc976255b47e0


이것은 Android 테스트 용 Kotlin에서 사용중인 도우미입니다. 제 경우에는 longOperation을 사용하여 서버 응답을 모방하지만 목적에 맞게 조정할 수 있습니다.

@Test
fun ensureItemDetailIsCalledForRowClicked() {
    onView(withId(R.id.input_text))
        .perform(ViewActions.typeText(""), ViewActions.closeSoftKeyboard())
    onView(withId(R.id.search_icon)).perform(ViewActions.click())
    longOperation(
        longOperation = { Thread.sleep(1000) },
        callback = {onView(withId(R.id.result_list)).check(isVisible())})
}

private fun longOperation(
    longOperation: ()-> Unit,
    callback: ()-> Unit
){
    Thread{
        longOperation()
        callback()
    }.start()
}

이 작업을 믹스에 추가하겠습니다.

fun suspendUntilSuccess(actionToSucceed: () -> Unit, iteration : Int = 0) {
    try {
        actionToSucceed.invoke()
    } catch (e: Throwable) {
        Thread.sleep(200)
        val incrementedIteration : Int = iteration + 1
        if (incrementedIteration == 25) {
            fail("Failed after waiting for action to succeed for 5 seconds.")
        }
        suspendUntilSuccess(actionToSucceed, incrementedIteration)
    }
}

다음과 같이 호출됩니다.

suspendUntilSuccess({
    checkThat.viewIsVisible(R.id.textView)
})

최대 반복, 반복 길이 등과 같은 매개 변수를 suspendUntilSuccess 함수에 추가 할 수 있습니다.

나는 여전히 유휴 리소스를 사용하는 것을 선호하지만, 예를 들어 장치의 느린 애니메이션으로 인해 테스트가 작동 할 때이 기능을 사용하고 잘 작동합니다. 물론 실패하기 전처럼 최대 5 초 동안 멈출 수 있으므로 성공하려는 작업이 성공하지 못할 경우 테스트 실행 시간이 늘어날 수 있습니다.

참고 URL : https://stackoverflow.com/questions/21417954/espresso-thread-sleep

반응형