android Espresso测试被后台线程阻止,应用程序未空闲异常:“应用程序空闲异常,”

ftf50wuq  于 2023-01-07  发布在  Android
关注(0)|答案(3)|浏览(142)

我的android espresso单元测试由于一些后台线程不空闲而被阻塞。我怎么知道是哪个线程阻塞了我的应用程序的执行?

android.support.test.espresso.AppNotIdleException: Looped for 246 iterations over 60 SECONDS. The following Idle Conditions failed ASYNC_TASKS_HAVE_IDLED.
        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:580)
        at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:92)
        at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:56)
        at android.support.test.espresso.ViewInteraction.runSynchronouslyOnUiThread(ViewInteraction.java:184)
        at android.support.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:115)
        at android.support.test.espresso.ViewInteraction.perform(ViewInteraction.java:87)
        at android.support.test.espresso.Espresso.closeSoftKeyboard(Espresso.java:159)
hmae6n7t

hmae6n7t1#

作为开始:
Espresso for Android是一个完美而快速的测试自动化框架,但它有一个重要的限制--只允许您在测试上下文下在应用内部操作。
出发地:http://qathread.blogspot.com/2015/05/espresso-uiautomator-perfect-tandem.html
这意味着执行任何操作的Espresso都需要在应用程序的主线程上操作。它检查UI线程何时为idle(),如果不是,它将等待UI线程再次空闲。
如果UI线程空闲时间不长,则会产生Espressso IdlingResources错误,如AppNotIdleException,这意味着:
指示应用程序即使在指定的持续时间后也未空闲的异常。
要解决这个问题,您需要创建自己的IdlingResource方法,在UI线程为idle()时使用Espresso
让我们更深入地看看这个问题:
Espresso引入了IdlingResource的概念,这是一个简单的接口,可以:
表示被测应用程序的资源,该资源可能导致在测试执行期间发生异步后台工作
接口定义了三个方法:

  • getName():必须返回一个非空字符串,用于标识空闲资源。
  • 当前空闲():返回空闲资源的当前空闲状态。如果它返回true,则

注册的ResourceCallback之前必须已调用。

  • 注册表空闲转换回调(空闲资源.资源回调回调):此方法通常用于存储对

回调通知它空闲状态的变化。
例如,等待页面完全加载到WebView中的空闲资源的实现如下所示:

public class WebViewIdlingResource extends WebChromeClient implements IdlingResource {

    private static final int FINISHED = 100;

    private WebView webView;
    private ResourceCallback callback;

    private WebViewIdlingResource(WebView webView) {
        this.webView = checkNotNull(webView,
                String.format("Trying to instantiate a \'%s\' with a null WebView", getName())));
        // Shall we save the original client? Atm it's not used though.
        this.webView.setWebChromeClient(this);
    }

    @Override public void onProgressChanged(WebView view, int newProgress) {
        if (newProgress == FINISHED && view.getTitle() != null && callback != null) {
            callback.onTransitionToIdle();
        }
    }

    @Override public void onReceivedTitle(WebView view, String title) {
        if (webView.getProgress() == FINISHED && callback != null) {
            callback.onTransitionToIdle();
        }
    }

    @Override public String getName() {
        return "WebView idling resource";
    }

    @Override public boolean isIdleNow() {
        // The webView hasn't been injected yet, so we're idling
        if (webView == null) return true;
        return webView.getProgress() == FINISHED && webView.getTitle() != null;
    }

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

在创建了自己的自定义空闲资源之后,需要通过调用Espresso.registerIdlingResource(webViewIdlingResource)向Espresso注册它。
出发地:http://dev.jimdo.com/2014/05/09/wait-for-it-a-deep-dive-into-espresso-s-idling-resources/
如果它不起作用,尝试与Espresso一起使用另一个名为[uiatomator的Google测试框架,它可能会帮助您处理这个问题。
希望能有所帮助

kb5ga3dv

kb5ga3dv2#

你可以创建一个线程转储来查看是什么阻止了你的应用。有时候,创建多个线程转储会有所帮助。

hof1towb

hof1towb3#

我也遇到了同样的问题。我编写了一个DumThreadRule来在测试失败的情况下转储线程。如果有人需要这个代码,下面是代码:

class DumpThreadRule() : TestWatcher() {
    private fun dumpThreads() {
        val threads = Thread.getAllStackTraces()
        threads.forEach {
            System.err.println(it.key.getName() + ": " + it.key.getState())
            for (stackTraceElement in it.key.getStackTrace()) {
                System.err.println("\t" + stackTraceElement)
            }
        }
    }

    override fun failed(e: Throwable?, description: Description?) {
        super.failed(e, description)
        dumpThreads()
    }
}

您可以在测试中使用:

@Rule
@JvmField
var dumpThreadRule = DumpThreadRule()

然而,在我的例子中,所有的线程都是“运行”,“定时等待”或“等待”。他们都不是“运行”。因此我的UI线程应该是“空闲”不是吗?

相关问题