问题
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