Espresso test blocked with background thread. Application not idle Exception: “AppNotIdleException.”

北战南征 提交于 2021-01-27 11:28:05

问题


My android espresso unit test blocked due to some background thread not idle. How can i figure out which thread is blocking my application to execute?

        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)

回答1:


As a beginning:

Espresso for Android is perfect and fast test automation framework, but it has one important limitation - you are allowed to operate only inside your app under test context.

From: http://qathread.blogspot.com/2015/05/espresso-uiautomator-perfect-tandem.html

It means that Espresso for perform any action needs to operate on main thread of app. It checks when UI thread is idle() and if not it waits until UI thread would be idle again.

If UI Thread is not idle too long, it produces Espressso IdlingResources errors like AppNotIdleException, which means:

An exception which indicates that the App has not become idle even after the specified duration.

To deal with this problem you need to create your own IdlingResource method to say Espresso when UI thread would be idle() for it.

Let's take a look a bit deeper into problem:

Espresso introduces the concept of IdlingResource, which is a simple interface that:

Represents a resource of an application under test which can cause asynchronous background work to happen during test execution

The interface defines three methods:

  • getName(): must return a non-null string that identifies an idling resource.
  • isIdleNow(): returns the current idle state of the idling resource. If it returns true, the onTransitionToIdle() method on the
    registered ResourceCallback must have been previously called.
  • registerIdleTransitionCallback(IdlingResource.ResourceCallback callback): normally this method is used to store a reference to the
    callback to notify it of a change in the idle state.

For example, an implementation for an idling resource that waits for a page to be fully loaded in a WebView will look something like this:

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

After creating your own custom idling resource, it needs to be registered with Espresso by calling Espresso.registerIdlingResource(webViewIdlingResource).

From:http://dev.jimdo.com/2014/05/09/wait-for-it-a-deep-dive-into-espresso-s-idling-resources/

If it won't work try to use along with Espresso another Google test framework called [uiatomator, which may help you to deal with this problem.

Hope it will help




回答2:


You can create a thread dump to see what is blocking your app. Sometimes it help when you create more than one thread dump.



来源:https://stackoverflow.com/questions/39485193/espresso-test-blocked-with-background-thread-application-not-idle-exception-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!