首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >有没有可能使用Espresso的IdlingResource来等待某个视图出现?

有没有可能使用Espresso的IdlingResource来等待某个视图出现?
EN

Stack Overflow用户
提问于 2018-05-31 23:48:56
回答 3查看 9.2K关注 0票数 11

在我的测试中,我有一个阶段,在按下按钮后,应用程序会对云服务执行大量异步计算和请求,之后它会显示某个视图。

是否可以使用Espresso的IdlingResource实现来等待某个视图出现?

我读过一个answers here,评论似乎建议你可以使用IdlingResource,但我不明白是怎么回事。Espresso似乎没有任何内置的方法来处理长时间的操作,但必须编写自己的等待循环感觉就像一个黑客。

有没有办法解决这个问题,或者我应该像链接的帖子中的答案那样做?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-06-01 03:53:28

您的IdlingResource可能如下所示:

代码语言:javascript
复制
import android.support.test.espresso.IdlingResource;
import android.support.test.espresso.ViewFinder;
import android.support.test.espresso.ViewInteraction;
import android.view.View;

import org.hamcrest.Matcher;

import java.lang.reflect.Field;

import static android.support.test.espresso.Espresso.onView;

public class ViewShownIdlingResource implements IdlingResource {

    private static final String TAG = ViewShownIdlingResource.class.getSimpleName();

    private final Matcher<View> viewMatcher;
    private ResourceCallback resourceCallback;

    public ViewShownIdlingResource(final Matcher<View> viewMatcher) {
        this.viewMatcher = viewMatcher;
    }

    @Override
    public boolean isIdleNow() {
        View view = getView(viewMatcher);
        boolean idle = view == null || view.isShown();

        if (idle && resourceCallback != null) {
            resourceCallback.onTransitionToIdle();
        }

        return idle;
    }

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

    @Override
    public String getName() {
        return this + viewMatcher.toString();
    }

    private static View getView(Matcher<View> viewMatcher) {
        try {
            ViewInteraction viewInteraction = onView(viewMatcher);
            Field finderField = viewInteraction.getClass().getDeclaredField("viewFinder");
            finderField.setAccessible(true);
            ViewFinder finder = (ViewFinder) finderField.get(viewInteraction);
            return finder.getView();
        } catch (Exception e) {
            return null;
        }
    }
}

然后,您可以创建一个等待视图的辅助方法:

代码语言:javascript
复制
public void waitViewShown(Matcher<View> matcher) {
    IdlingResource idlingResource = new ViewShownIdlingResource(matcher);///
    try {
        IdlingRegistry.getInstance().register(idlingResource);
        onView(matcher).check(matches(isDisplayed()));  
    } finally {
        IdlingRegistry.getInstance().unregister(idlingResource);
    }    
}

最后,在您的测试中:

代码语言:javascript
复制
@Test
public void someTest() {
    waitViewShown(withId(R.id.<some>));

    //do whatever verification needed afterwards    
} 

您可以通过让IdlingResource等待任何条件来改进此示例,而不仅仅是可见性条件。

票数 12
EN

Stack Overflow用户

发布于 2019-01-17 16:32:43

我从Anatolii获得了灵感,但我仍然只使用ViewMatchers,而不是使用View.class中的方法。

代码语言:javascript
复制
/**
 * {@link IdlingResource} that idles until a {@link View} condition is fulfilled.
 */
public class ViewIdlingResource implements IdlingResource {

    private final Matcher<View>    viewMatcher;
    private final Matcher<View>    idleMatcher;
    private       ResourceCallback resourceCallback;

    /**
     * Constructor.
     *
     * @param viewMatcher The matcher to find the view.
     * @param idlerMatcher The matcher condition to be fulfilled to be considered idle.
     */
    public ViewIdlingResource(final Matcher<View> viewMatcher, Matcher<View> idlerMatcher) {
        this.viewMatcher = viewMatcher;
        this.idleMatcher = idlerMatcher;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isIdleNow() {
        View view = getView(viewMatcher);
        boolean isIdle = idleMatcher.matches(view);

        if (isIdle && resourceCallback != null) {
            resourceCallback.onTransitionToIdle();
        }

        return isIdle;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        this.resourceCallback = resourceCallback;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getName() {
        return this + viewMatcher.toString();
    }

    /**
     * Tries to find the view associated with the given {@link Matcher<View>}.
     */
    private static View getView(Matcher<View> viewMatcher) {
        try {
            ViewInteraction viewInteraction = onView(viewMatcher);
            Field finderField = viewInteraction.getClass().getDeclaredField("viewFinder");
            finderField.setAccessible(true);
            ViewFinder finder = (ViewFinder) finderField.get(viewInteraction);
            return finder.getView();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

以及如何在测试用例中使用空闲程序,我将ViewMatchers.isDisplayed()作为我在空闲程序中的预期条件。

代码语言:javascript
复制
private void waitUntilViewIsDisplayed(Matcher<View> matcher) {
        IdlingResource idlingResource = new ViewIdlingResource(matcher, isDisplayed());
        try {
            IdlingRegistry.getInstance().register(idlingResource);
            // First call to onView is to trigger the idler.
            onView(withId(0)).check(doesNotExist());
        } finally {
            IdlingRegistry.getInstance().unregister(idlingResource);
        }
    }

这样,您就可以将任何Matcher.class传递给ViewIdlingResource构造函数,作为viewMatcher参数找到的视图所需的条件。

票数 4
EN

Stack Overflow用户

发布于 2020-03-19 16:59:13

以等待视图显示,并可以对其执行操作。您可以使用此方法:

代码语言:javascript
复制
    private const val sleepTime = 1000L
    private const val maximumWaitedTime = 10000L // maximum waited time in milliseconds to wait a view visible

    fun waitViewVisible(viewInteraction: ViewInteraction?, block: (() -> Unit)? = null) {
        waitAssertView(viewInteraction, ViewAssertions.matches(isDisplayed()), block)
    }

    fun waitViewGone(viewInteraction: ViewInteraction?, block: (() -> Unit)? = null) {
        waitAssertView(viewInteraction, ViewAssertions.matches(not(isDisplayed())), block)
    }

    fun waitAssertView(viewInteraction: ViewInteraction?, assertion: ViewAssertion?, block: (() -> Unit)? = null) {
            if (viewInteraction == null || assertion == null) throw NullPointerException()
            val startedTime: Long = System.currentTimeMillis()
            var elapsedTime: Long = 0
            var isVisible = false
            do {
                isVisible = runCatching {
                    viewInteraction.check(assertion)
                }.isSuccess
                if (isVisible) break
                Thread.sleep(sleepTime)
                elapsedTime = System.currentTimeMillis() - startedTime
            } while (elapsedTime <= maximumWaitedTime)
            if (!isVisible) throw TimeoutException("Waited time exceed the maximum waited time")

            block?.invoke()
        }
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50628219

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档