এসপ্রেসো: থ্রেড.স্লিপ ();


102

এসপ্রেসো দাবি করেন যে এর জন্য কোনও প্রয়োজন নেই Thread.sleep();, তবে আমি কোডটি অন্তর্ভুক্ত না করে আমার কোড কাজ করে না। আমি একটি আইপি সংযোগ করছি। সংযোগ করার সময়, একটি অগ্রগতি ডায়ালগ প্রদর্শিত হয়। আমার 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();এবং এখনও ভাগ্যবান নয়।

এটি কি এই একমাত্র উপায়? নাকি আমি কিছু মিস করছি?

আগাম ধন্যবাদ.


লুপ কীভাবে যেভাবেই হোক আপনি ব্লকিং কল করতে চান তাতে কী অযাচিত রাখা সম্ভব?
কেদার্ক

ঠিক আছে .. আমাকে ব্যাখ্যা করতে দিন। আপনার জন্য 2 টি পরামর্শ 1 ম) কল-ব্যাক জাতীয় প্রক্রিয়া জাতীয় কিছু বাস্তবায়ন করুন। অন-কানেকশন-ইনস্টল কল করুন একটি পদ্ধতি এবং দেখুন প্রদর্শন the 2 য়) আপনি IP.enterIP () এর মধ্যে বিলম্ব তৈরি করতে চান; এবং অনভিউ (....) যাতে আপনি সময় লুপটি রাখতে পারেন যা অনভিউ (..) কল করতে সিমিলার ধরণের বিলম্ব তৈরি করবে ... তবে আমি অনুভব করি যদি সম্ভব হয় তবে অনুগ্রহ করে নং 1 পছন্দ করুন (কল-ব্যাক তৈরি করা) মেকানিজম) ...
কেদার্ক

@kedark হ্যাঁ এটি একটি বিকল্প, তবে এটিই কি এস্প্রেসো সমাধান?
চাদ বিংহাম

আপনার প্রশ্নে অনুत्तरযুক্ত মন্তব্য রয়েছে, আপনি কি তাদের উত্তর দিতে পারবেন?
বলহোস

@ বলহসো, কি প্রশ্ন?
চাদ বিংহাম

উত্তর:


110

আমার মনে সঠিক পন্থা হবে:

/** 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)));

3
ধন্যবাদ অ্যালেক্স, আপনি কেন এই বিকল্পটি আইডলিংসোর্স বা অ্যাসিঙ্কটাস্কের চেয়ে বেছে নিলেন?
টিম বোল্যান্ড

1
এটি কার্যনির্বাহী পদ্ধতি, বেশিরভাগ ক্ষেত্রে এস্প্রেসো কোনও সমস্যা এবং বিশেষ 'ওয়েট কোড' ছাড়াই কাজ করছেন। আমি আসলে বেশ কয়েকটি বিভিন্ন উপায়ে চেষ্টা করে দেখি এবং মনে করি এটি একটি সর্বাধিক মিলে যাওয়া এসপ্রেসো আর্কিটেকচার / ডিজাইন।
ওলেকসান্ডার কুচেরেঙ্কো

1
@ অ্যালেক্স আমার এই দিনের সাথী করেছে!
দাউদ gdanski

1
আমার জন্য, এটি এপিআই <= 19 এর জন্য ব্যর্থ হয়েছে, নতুন পারফর্ম এক্সেপশন-লাইনে ফেলে দিন B বিল্ডার ()
প্রবিন টিমসিনা

4
আমি আশা করি আপনি বুঝতে পারছেন যে এটির একটি নমুনা, আপনি নিজের প্রয়োজনের জন্য অনুলিপি / আটকানো এবং সংশোধন করতে পারেন। এটি নিজের ব্যবসায়ের প্রয়োজনে সঠিকভাবে ব্যবহার করার দায়িত্ব আপনার নয়, আমার নয়।
ওলেকসান্ডার কুচেরেঙ্কো

47

অ্যালেক্সকে তার দুর্দান্ত উত্তরের জন্য ধন্যবাদ। এমন কিছু মামলা রয়েছে যা আপনাকে কোডে কিছুটা বিলম্ব করতে হবে। এটি অগত্যা সার্ভারের প্রতিক্রিয়ার জন্য অপেক্ষা করছে না তবে অ্যানিমেশনটি সম্পন্ন হওয়ার জন্য অপেক্ষা করছে। আমার ব্যক্তিগতভাবে এসপ্রেসো আইডলিং রিসোর্সগুলিতে সমস্যা আছে (আমি মনে করি আমরা কোনও সাধারণ জিনিসের জন্য কোডের অনেকগুলি লাইন লিখছি) তাই আমি আলেকসকে নিম্নলিখিত কোডগুলিতে করার পদ্ধতিটি পরিবর্তন করেছি:

/**
 * 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));


7
পারফর্ম পদ্ধতিটি এই জাতীয় এক লাইনের সাহায্যে সরল করা যায়: uiController.loopMainThreadForAtLeast (মিলিস);
ইয়ার কুকিলকা

জট্টিল, আমি তা জানতাম না: @YairKukielka thumbs_up
Hesam

ব্যস্ত অপেক্ষার জন্য হাই
TWiStErRob

অসাধারণ. আমি যুগে যুগে এটি অনুসন্ধান করছিলাম। অপেক্ষার সমস্যার জন্য সহজ সমাধানের জন্য +1।
টোবিয়াস রিখ

ব্যবহারের পরিবর্তে বিলম্ব যুক্ত করার আরও অনেক ভাল উপায়Thread.sleep()
ওয়াহিব উল হক

23

আমি যখন কোনও সার্ভারের প্রতিক্রিয়ার জন্য অপেক্ষা করছিলাম এবং প্রতিক্রিয়ার ভিত্তিতে উপাদানগুলির দৃশ্যমানতার পরিবর্তন করছিলাম তখন একই ধরণের সমস্যার উত্তর খুঁজতে গিয়ে আমি এই থ্রেডে হোঁচট খেয়েছি।

উপরের সমাধানটি অবশ্যই স্পষ্টভাবে সহায়তা করেছিল, আমি শেষ পর্যন্ত চিউকির কাছ থেকে এই দুর্দান্ত উদাহরণটি পেয়েছি এবং যখনই আমি অ্যাপ্লিকেশন নিষ্ক্রিয় সময়কালে ক্রিয়াকলাপের জন্য অপেক্ষা করি তখনই আমার এই পন্থাটি আমার গোপনে ব্যবহার করুন।

আমি আমার নিজস্ব ইউটিলিটি ক্লাসে এল্যাপসডটাইমআইডলিং রিসোর্স () যুক্ত করেছি , এখন এটিকে কার্যকরভাবে একটি এসপ্রেসো-সঠিক বিকল্প হিসাবে ব্যবহার করতে পারি, এবং এখন ব্যবহারটি সুন্দর এবং পরিষ্কার:

// 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);

আমি একটি I/TestRunner: java.lang.NoClassDefFoundError: fr.x.app.y.testtools.ElapsedTimeIdlingResourceত্রুটি পেয়েছি । কোন ধারণা. আমি প্রোগার্ড ব্যবহার করি তবে অবজ্ঞা নিষ্ক্রিয় করে।
অ্যান্টনি

-keepক্লাসগুলির জন্য একটি বিবৃতি যুক্ত করার চেষ্টা করুন যা প্রোগ্রার্ড তাদের অপ্রয়োজনীয় হিসাবে সরছে না তা নিশ্চিত করার জন্য এটি পাওয়া যায় না। এখানে আরও তথ্য: developer.android.com/tools/help/proguard.html#
keep

আমি স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / 6868৮৫৯৫২৮/২ পোস্ট করি । ক্লাসটি seed.txt এবং ম্যাপিং. টেক্সটে রয়েছে
অ্যান্থনি

2
যদি আপনাকে অলস নীতিগুলি পরিবর্তন করতে হয় তবে আপনি সম্ভবত অলস সংস্থানগুলি সঠিকভাবে প্রয়োগ করছেন না। দীর্ঘমেয়াদে এটি স্থির করতে সময় বিনিয়োগ করা আরও ভাল। এই পদ্ধতিটি শেষ পর্যন্ত ধীর এবং ফ্ল্যাশ পরীক্ষার দিকে পরিচালিত করবে। পরীক্ষা করে দেখুন google.github.io/android-testing-support-library/docs/espresso/...
জোসে Alcérreca

আপনি বেশ ঠিক বলেছেন। এই উত্তরটি এক বছরেরও বেশি পুরনো, এবং তখন থেকে অলস সংস্থানগুলির ব্যবহারের এমন উন্নতি হয়েছে যে আমি উপরের কোডটি ব্যবহার করেছি একইভাবে ব্যবহারযোগ্য বাক্সটি বাক্সের বাইরে কাজ করে, সঠিকভাবে উপহাসিত API ক্লায়েন্ট সনাক্ত করে - আমরা আর উপরের ব্যবহার করি না এজন্য আমাদের চালিত পরীক্ষায় এলপাসডটাইমআইডলিং রিসোর্স। (আপনি অবশ্যই Rx সমস্ত জিনিস করতে পারেন, যা একটি অপেক্ষা সময়ের মধ্যে হ্যাক করার প্রয়োজনকে অস্বীকার করে)। এটি বলেছিল, গুগল জিনিসগুলি করার পদ্ধতি সর্বদা সেরা নয়: দার্শনিকহ্যাকার / পোস্ট /
ম্যাটম্যাট

18

আমি মনে করি এই লাইনটি যুক্ত করা আরও সহজ:

SystemClock.sleep(1500);

ফেরার আগে প্রদত্ত সংখ্যক মিলিসেকেন্ডের (আপটাইমমিলিসের) অপেক্ষা করে its ঘুমের মতো (দীর্ঘ), তবে ইন্টারপ্রেডএক্সসেপশন ছুঁড়ে না; বিঘ্নিত () ইভেন্টগুলি পরবর্তী বিঘ্নিত অপারেশন পর্যন্ত স্থগিত করা হয়। কমপক্ষে নির্দিষ্ট সংখ্যক মিলিসেকেন্ডগুলি অতিক্রান্ত না হওয়া পর্যন্ত ফিরে আসে না।


এক্সপ্রেসো হ'ল এই হার্ডকোডযুক্ত ঘুম এড়ানোর জন্য যা ফলক পরীক্ষার সৃষ্টি করে। যদি এটি হয় তবে আমি পাশাপাশি অ্যাপিয়ামের মতো ব্ল্যাকবক্স সরঞ্জামগুলিও যেতে পারি
এমজে

6

আপনি কেবল বারিস্তা পদ্ধতি ব্যবহার করতে পারেন:

BaristaSleepActions.sleep(2000);

BaristaSleepActions.sleep(2, SECONDS);

বারিস্তা হ'ল একটি গ্রন্থাগার যা গৃহীত উত্তরের প্রয়োজনীয় সমস্ত কোড যুক্ত করা এড়াতে এসপ্রেসোকে মোড় দেয়। এবং এখানে একটি লিঙ্ক! https://github.com/SchibstedSpain/Barista


আমি এই এবং কেবল একটি থ্রেড ঘুমের মধ্যে পার্থক্য পাচ্ছি না
পাবলো ক্যাভিগলিয়া

সত্যিই, আমি মনে করি না গুগলের কোন ভিডিওতে একজন লোক বলেছিল যে আমাদের সাধারণ করার পরিবর্তে ঘুমানোর জন্য এই উপায়টি ব্যবহার করা উচিত Thread.sleep()। দুঃখিত! গুগল এসপ্রেসো সম্পর্কে তৈরি প্রথম ভিডিওগুলির মধ্যে কিছু ছিল তবে আমি মনে করি না কোনটি ... এটি কয়েক বছর আগে ছিল। দুঃখিত! :·) উহু! সম্পাদনা করুন! আমি ভিডিওটির লিঙ্কটি তিন বছর আগে খোলার পিআরটিতে রেখেছি। এটা দেখ! github.com/AdevintaSpain/Barista/pull/19
রক

5

এটি এই উত্তরের অনুরূপ তবে প্রয়াসের পরিবর্তে একটি সময়সীমা ব্যবহার করে এবং অন্যান্য ভিউআইন্টেরাকেশনে শৃঙ্খলিত হতে পারে:

/**
 * 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())

4

আমি কোডিং এবং এসপ্রেসোতে নতুন, সুতরাং আমি জানি যে ভাল এবং যুক্তিসঙ্গত সমাধানটি আইডলিং ব্যবহার করা, আমি এখনও এটি করতে যথেষ্ট বুদ্ধিমান নই।

যতক্ষণ না আমি আরও জ্ঞানী হয়ে উঠি, তবুও আমার পরীক্ষাগুলি কোনওভাবে চালানো দরকার, সুতরাং আপাতত আমি এই নোংরা সমাধানটি ব্যবহার করছি যা একটি উপাদান অনুসন্ধান করার জন্য অনেক চেষ্টা করে, এটি খুঁজে পেলে থামে এবং যদি না হয়, সংক্ষেপে ঘুমে এবং শুরু হয় আবার যতক্ষণ না এটি প্রচেষ্টা সর্বাধিক এনআরআর পৌঁছেছে (এখন পর্যন্ত সর্বাধিক প্রচেষ্টার সংখ্যা প্রায় 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;
}

আমি এটি সমস্ত পদ্ধতিতে ব্যবহার করছি যা আইডি, পাঠ্য, প্যারেন্ট ইত্যাদি দ্বারা উপাদানগুলি সন্ধান করছে:

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

আপনার উদাহরণস্বরূপ, findById(int itemId)পদ্ধতিটি একটি উপাদান (যা NULL হতে পারে) waitForElementUntilDisplayed(element);ফেরত আসবে কিনা সত্য তা মিথ্যা .... তবে, এটি ঠিক নয়
এমবিব

কেবল চিম ইন করে বলতে চেয়েছিলেন এটি আমার মতে সেরা সমাধান। IdlingResource5 সেকেন্ডের পোলিং রেট গ্রানুলারিটির কারণে আমার পক্ষে যথেষ্ট নয় (আমার ব্যবহারের ক্ষেত্রে খুব বড় উপায়)। গৃহীত উত্তরটি আমার পক্ষে কার্যকর হয় না (কেন ইতিমধ্যে উত্তরটির দীর্ঘ মন্তব্য ফিডে অন্তর্ভুক্ত করা হয়েছে তার ব্যাখ্যা)। এর জন্য ধন্যবাদ! আমি আপনার ধারণা নিয়েছি এবং আমার নিজস্ব সমাধান তৈরি করেছি এবং এটি একটি কবজির মতো কাজ করে।
ওসকামায়

হ্যাঁ, এখনকার ক্রিয়াকলাপে নেই এমন উপাদানগুলির জন্য অপেক্ষা করতে চাইলে এটিই আমার জন্য একমাত্র সমাধান।
guilhermekrz

3

পরীক্ষাগুলিতে ঘুম () কল এড়াতে এসপ্রেসো নির্মিত হয়। আপনার পরীক্ষায় কোনও আইপি প্রবেশের জন্য একটি ডায়ালগ খোলা উচিত নয়, এটি পরীক্ষিত ক্রিয়াকলাপের দায়বদ্ধতা হওয়া উচিত।

অন্যদিকে, আপনার ইউআই পরীক্ষার উচিত:

  • আইপি ডায়ালগটি উপস্থিত হওয়ার জন্য অপেক্ষা করুন
  • আইপি ঠিকানা পূরণ করুন এবং এন্টার ক্লিক করুন
  • আপনার বোতামটি উপস্থিত হওয়ার জন্য অপেক্ষা করুন এবং এটি ক্লিক করুন

পরীক্ষার মতো কিছু দেখতে হবে:

// 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());

আপনার পরীক্ষাগুলি কার্যকর করার আগে ইউএস থ্রেড এবং অ্যাসিঙ্কটাস্ক পুল উভয়ের মধ্যে যা ঘটছে তা এসপ্রেসো অপেক্ষা করে।

মনে রাখবেন যে আপনার পরীক্ষাগুলি এমন কোনও কিছু করা উচিত নয় যা আপনার আবেদনের দায়বদ্ধতা। এটি একটি "সুবিদিত ব্যবহারকারী" এর মতো আচরণ করা উচিত: যে ব্যবহারকারী ক্লিক করে, স্ক্রিনে কিছু দেখানো হয়েছে তা যাচাই করে, তবে প্রকৃতপক্ষে, উপাদানগুলির আইডিগুলি জেনে রাখুন


2
আপনার উদাহরণ কোডটি মূলত আমার প্রশ্নে আমি লিখেছি একই কোড।
চাদ বিংহাম

@ বিঙ্গহামার যা বলতে চাইছি তা হ'ল পরীক্ষার ব্যবহারকারীর মতো আচরণ করা উচিত। আমি যে পয়েন্টটি মিস করছি তা হ'ল আপনার আইপি.এনএনআরআইপি () পদ্ধতিটি যা করে। আপনি কি আপনার প্রশ্ন সম্পাদনা করতে পারেন এবং তা পরিষ্কার করতে পারেন?
বলহসো

আমার মন্তব্যগুলি যা বলে তা বলে। এটি এস্প্রেসোতে কেবল একটি পদ্ধতি যা আইপি ডায়ালগটি পূরণ করে। এটি সমস্ত ইউআই।
চাদ বিংহাম

মিমি ... ঠিক আছে, তাই আপনি ঠিক বলেছেন আমার পরীক্ষাটিও মূলত একই করছে। আপনি কি ইউআই থ্রেড বা অ্যাসিঙ্কটাস্কের বাইরে কিছু করেন?
বলহসো

16
এস্প্রেসো এই উত্তরের কোড এবং পাঠ্যের মতো কাজ করে না বলে মনে হয়। প্রদত্ত ম্যাচার সফল না হওয়া পর্যন্ত ভিউইন্টেকারেশনে একটি চেক কল অপেক্ষা করবে না, তবে শর্তটি পূরণ না হলে অবিলম্বে ব্যর্থ হবে। এটি করার সঠিক উপায়টি হ'ল হয় এই সাইক্যানটাস্কগুলি ব্যবহার করা, যেমন এই উত্তরে উল্লিখিত হয়েছে, বা যদি কোনওভাবে সম্ভব না হয় তবে একটি আইডলিং রিসোর্স বাস্তবায়ন করুন যা পরীক্ষার কার্যকারিতাটি চালিয়ে যাওয়া ঠিক হবে যখন ঠিক করা হয় সে সম্পর্কে এসপ্রেসির ইউআইকন্ট্রোলারকে অবহিত করবে।
হাফ্যাক্স

2

আপনার এসপ্রেসো আইডলিং রিসোর্স ব্যবহার করা উচিত, এটি এই কোডল্যাবে প্রস্তাবিত

একটি অলস সংস্থান একটি অ্যাসিক্রোনাস অপারেশন প্রতিনিধিত্ব করে যার ফলাফলগুলি ইউআই পরীক্ষায় পরবর্তী ক্রিয়াকলাপগুলিকে প্রভাবিত করে। এসপ্রেসোর সাথে অলস সংস্থানগুলি নিবন্ধভুক্ত করে, আপনি আপনার অ্যাপ্লিকেশন পরীক্ষা করার সময় এই অ্যাসিনক্রোনাস অপারেশনগুলিকে আরও নির্ভরযোগ্যতার সাথে বৈধতা দিতে পারেন।

উপস্থাপকের কাছ থেকে অ্যাসিক্রোনাস কলের উদাহরণ

@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'

Android এর জন্য

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

আইডলিংসোর্স উদাহরণ: https://github.com/googlesults/android-testing/tree/master/ui/espresso/IdlingResourceSample


0

যদিও আমি মনে করি এটির জন্য আইডলিং রিসোর্সগুলি ব্যবহার করা ভাল ( 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());

এটি আপনাকে ক্রিয়াকলাপ দেখার জন্য এবং দৃ time়তার সাথে দেখার সময়সীমা যুক্ত করার অনুমতি দেয়।


যেকোন টেস্ট এসপ্রেসো পরীক্ষার ক্ষেত্রে ডিলির জন্য কোডের একক লাইন নীচে এটি ব্যবহার করুন: সিস্টেমক্লক.স্লিপ (1000); // 1 দ্বিতীয়
নিকুঞ্জকুমার কাপুপাড়া

আমার জন্য এই শুধুমাত্র এই লাইন পরিবর্তন করে কাজ করে return new TimedViewInteraction(Espresso.onView(viewMatcher));দিয়েreturn new TimedViewInteraction(Espresso.onView(viewMatcher).check(matches(isDisplayed())));
ম্যানুয়েল Schmitzberger

0

আমার ইউটিলিটি চালনাযোগ্য বা কলযোগ্য এক্সিকিউটিকে পুনরাবৃত্তি করে যতক্ষণ না এটি ত্রুটি ছাড়াই পাস না করে বা একটি টাইমআউটের পরে থ্রোয়েবল নিক্ষেপ করে। এটি এসপ্রেসো পরীক্ষার জন্য পুরোপুরি কাজ করে!

ধরা যাক শেষ দৃশ্যের ইন্টারঅ্যাকশন (বোতাম ক্লিক) কিছু ব্যাকগ্রাউন্ড থ্রেড (নেটওয়ার্ক, ডাটাবেস ইত্যাদি) সক্রিয় করে। ফলস্বরূপ, একটি নতুন স্ক্রিন প্রদর্শিত হবে এবং আমরা এটি আমাদের পরবর্তী ধাপে এটি চেক করতে চাই, তবে নতুন পর্দা কখন পরীক্ষা করার জন্য প্রস্তুত হবে তা আমরা জানি না।

প্রস্তাবিত পদ্ধতির হ'ল আপনার অ্যাপ্লিকেশনটিকে আপনার পরীক্ষায় থ্রেডের রাজ্য সম্পর্কে বার্তা প্রেরণে বাধ্য করা। কখনও কখনও আমরা ওকে এইচটিটিপিআইআইডলিং রিসোর্সের মতো অন্তর্নির্মিত প্রক্রিয়াগুলি ব্যবহার করতে পারি। অন্যান্য ক্ষেত্রে, আপনার কেবলমাত্র সমর্থন পরীক্ষার জন্য আপনার অ্যাপ্লিকেশন উত্সগুলির বিভিন্ন জায়গায় কোড টুকরা সন্নিবেশ করা উচিত (আপনার অ্যাপ্লিকেশনটি যুক্তিযুক্ত হওয়া উচিত!) তদুপরি, আমাদের আপনার সমস্ত অ্যানিমেশনগুলি বন্ধ করা উচিত (যদিও এটি ইউআই এর অংশ)।

অন্যান্য পদ্ধতির অপেক্ষারত রয়েছে, যেমন সিস্টেমক্লক.স্লাইপ (10000)। তবে আমরা জানি না কতক্ষণ অপেক্ষা করতে হবে এমনকি দীর্ঘ বিলম্বও সাফল্যের গ্যারান্টি দিতে পারে না। অন্যদিকে, আপনার পরীক্ষা দীর্ঘস্থায়ী হবে।

আমার পদ্ধতির ইন্টারঅ্যাকশন দেখার জন্য সময় শর্ত যুক্ত করা। উদাহরণস্বরূপ আমরা পরীক্ষা করে দেখি যে নতুন স্ক্রিনটি 10000 এমসির (টাইমআউট) চলাকালীন উপস্থিত হওয়া উচিত। তবে আমরা যত তাড়াতাড়ি অপেক্ষা করতে চাই না এবং এটি যাচাই করি না (উদাহরণস্বরূপ প্রতি 100 এমএস) অবশ্যই আমরা পরীক্ষার থ্রেডটি এভাবে ব্লক করি, তবে সাধারণত আমাদের ক্ষেত্রে যেমন প্রয়োজন আমাদের কেবল এটিই।

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


0

এটি এমন একজন সহায়ক যা আমি অ্যান্ড্রয়েড পরীক্ষার জন্য কোটলিনে ব্যবহার করছি। আমার ক্ষেত্রে আমি সার্ভারের প্রতিক্রিয়ার নকল করতে লংওয়েপেশন ব্যবহার করছি তবে আপনি এটি আপনার উদ্দেশ্যটিতে সামঞ্জস্য করতে পারেন।

@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()
}

0

আমি মিশ্রণটিতে এটি করার আমার উপায় যুক্ত করব:

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)
})

আপনি সাসপেন্ড ইউটিটিলসাকসেস ফাংশনে সর্বাধিক পুনরাবৃত্তি, পুনরাবৃত্তির দৈর্ঘ্য ইত্যাদির মতো প্যারামিটার যুক্ত করতে পারেন।

আমি এখনও অলস সংস্থানগুলি ব্যবহার করতে পছন্দ করি তবে উদাহরণস্বরূপ ডিভাইসে ধীর অ্যানিমেশনগুলির কারণে যখন পরীক্ষাগুলি কাজ করে তখন আমি এই ফাংশনটি ব্যবহার করি এবং এটি ভালভাবে কাজ করে। এটি অবশ্যই ব্যর্থ হওয়ার আগে যেমন 5 সেকেন্ড অবধি ঝুলতে পারে, তাই যদি সফল হওয়ার পদক্ষেপটি কখনও সফল না হয় তবে এটি আপনার পরীক্ষাগুলির সম্পাদনের সময় বাড়িয়ে তুলতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.