在不冻结主线程的情况下在 Espresso Android 中进行延迟测试

Dmi*_* K. 4 java testing android qa android-espresso

我是 Espresso 测试框架的新手。现在我有一个任务来测试一些与异步后端一起工作的应用程序。当第一个活动开始时,一些片段只有在加载后才会出现。这可能需要几秒钟,所以最简单的方法是等待 5-7 秒。但是,使用 IdlingResource 会冻结主线程,因此在等待超时结束之前,我的后端数据无法加载。

这就是我使用 IdlingResource 的方式:

public static class ElapsedTimeIdlingResource implements IdlingResource {
    private final long startTime;
    private final long waitingTime;
    private ResourceCallback resourceCallback;

    ElapsedTimeIdlingResource(long waitingTime) {
        this.startTime = System.currentTimeMillis();
        this.waitingTime = waitingTime;
    }

    @Override
    public String getName() {
        return ElapsedTimeIdlingResource.class.getName() + ":" + waitingTime;
    }

    @Override
    public boolean isIdleNow() {
        long elapsed = System.currentTimeMillis() - startTime;
        boolean idle = (elapsed >= waitingTime);
        if (idle) resourceCallback.onTransitionToIdle();
        return idle;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        this.resourceCallback = resourceCallback;
    }
}
Run Code Online (Sandbox Code Playgroud)

我是这么称呼它的:

    long waitingTime = 5000;

    onView(withId(R.id.row_content)).check(matches(isDisplayed())).perform(click());

    IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
    IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);

    IdlingResource idlingResource = new ElapsedTimeIdlingResource(waitingTime);
    IdlingRegistry.getInstance().register(idlingResource);

   // .... do some tests

   IdlingRegistry.getInstance().unregister(idlingResource);
Run Code Online (Sandbox Code Playgroud)

如何在不阻塞主线程的情况下延迟测试执行?

Hai*_*lik 9

所以我有一个闪屏片段,它在延迟后处理到我正在测试的片段。@Aarons 回答有效。

onView(isRoot()).perform(waitFor(5000))
Run Code Online (Sandbox Code Playgroud)

科特林等待():

fun waitFor(delay: Long): ViewAction? {
    return object : ViewAction {
        override fun getConstraints(): Matcher<View> = isRoot()
        override fun getDescription(): String = "wait for $delay milliseconds"
        override fun perform(uiController: UiController, v: View?) {
            uiController.loopMainThreadForAtLeast(delay)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Aar*_*ron 8

如果您只想等待一段时间,则实际上并不需要 IdlingResource:

public static ViewAction waitFor(long delay) {
    return new ViewAction() {
        @Override public Matcher<View> getConstraints() {
            return ViewMatchers.isRoot();
        }

        @Override public String getDescription() {
            return "wait for " + delay + "milliseconds";
        }

        @Override public void perform(UiController uiController, View view) {
            uiController.loopMainThreadForAtLeast(delay);
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

onView(withId(R.id.row_content)).check(matches(isDisplayed())).perform(click());   
onView(isRoot()).perform(waitFor(5000);
Run Code Online (Sandbox Code Playgroud)

但是,如果您知道视图将在一段时间后出现,那么您可以使用 IdlingResource 例如:

public static ViewAction waitUntil(Matcher<View> matcher) {
    return actionWithAssertions(new ViewAction() {
        @Override public Matcher<View> getConstraints() {
            return ViewMatchers.isAssignableFrom(View.class);
        }

        @Override public String getDescription() {
            StringDescription description = new StringDescription();
            matcher.describeTo(description);
            return String.format("wait until: %s", description);
        }

        @Override public void perform(UiController uiController, View view) {
            if (!matcher.matches(view)) {
                LayoutChangeCallback callback = new LayoutChangeCallback(matcher);
                try {
                    IdlingRegistry.getInstance().register(callback);
                    view.addOnLayoutChangeListener(callback);
                    uiController.loopMainThreadUntilIdle();
                } finally {
                    view.removeOnLayoutChangeListener(callback);
                    IdlingRegistry.getInstance().unregister(callback);
                }
            }
        }
    });
}

private static class LayoutChangeCallback implements IdlingResource, View.OnLayoutChangeListener {

    private Matcher<View> matcher;
    private IdlingResource.ResourceCallback callback;
    private boolean matched = false;

    LayoutChangeCallback(Matcher<View> matcher) {
        this.matcher = matcher;
    }

    @Override public String getName() {
        return "Layout change callback";
    }

    @Override public boolean isIdleNow() {
        return matched;
    }

    @Override public void registerIdleTransitionCallback(ResourceCallback callback) {
        this.callback = callback;
    }

    @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        matched = matcher.matches(v);
        callback.onTransitionToIdle();
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用它例如:

onView(withId(R.id.row_content)).check(matches(isDisplayed())).perform(click());
onView(withId(R.id.main_content)).perform(waitUntil(isDisplayed()))
Run Code Online (Sandbox Code Playgroud)