tezvyn:

How would you implement and register a custom IdlingResource?

Curated by the Tezvyn teamSource: developer.android.comadvanced
How would you implement and register a custom IdlingResource?
WHAT IT TESTS

Whether you know Espresso's async contract.

ANSWER OUTLINE

Implement the three IdlingResource methods with an atomic counter; register via IdlingRegistry in setup and unregister in teardown.

RED FLAG

Suggesting Thread.sleep or polling loops.

WHAT THIS TESTS: Espresso is built on the assumption that the UI thread is idle between interactions. When a test triggers a background operation that later posts back to the UI, Espresso has no visibility into that work and will race ahead, causing flakes. This question probes whether you understand the IdlingResource contract and how to safely integrate it into the test lifecycle without leaking state or adding arbitrary delays.

A GOOD ANSWER COVERS: Four things in order. First, the three methods of the IdlingResource interface: getName must return a unique string so Espresso can identify the resource; isIdleNow must return true only when the background operation is truly finished; and registerIdleTransitionCallback must store a callback that your resource invokes when transitioning from busy to idle so Espresso can resume immediately rather than polling. Second, the state tracking mechanism. A CountingIdlingResource is the standard built-in helper that maintains an atomic integer counter; you increment before the background work starts and decrement when it completes, with isIdleNow returning true only when the count reaches zero. Third, registration and cleanup. You register the resource in a setup method such as @Before using IdlingRegistry.getInstance().register, and you must unregister it in @After to prevent the registry from holding a reference to a stale resource across tests. Fourth, scoping. The resource should wrap the specific API or operation that Espresso cannot see, such as a network dispatcher or database transaction runner, rather than blindly idling the entire application.

COMMON WRONG ANSWERS: Three red flags appear often. One is suggesting Thread.sleep or a busy loop to wait for the background task, which destroys test speed and reliability. Two is implementing isIdleNow correctly but forgetting to call the idle transition callback, which forces Espresso to poll and wastes CPU. Three is registering the resource once globally, for example in an Application subclass, which couples production code to test infrastructure and leaks the resource if the process survives multiple test suites.

LIKELY FOLLOW-UPS: Interviewers often push deeper. They may ask how you would handle a background task that completes before the resource is registered, which requires initializing the counter to zero and ensuring the callback fires only after registration. They may ask about thread safety, so you should mention that increment, decrement, and isIdleNow checks must be atomic or synchronized because the background thread and Espresso thread access the state concurrently. They may also ask about alternatives, such as using a custom TestRule to encapsulate registration and unregistration, or whether IdlingResource is still appropriate in a Compose world where SemanticsNodeInteraction and waitUntil exist.

ONE CONCRETE EXAMPLE: Suppose a repository triggers a Retrofit call and writes the result to Room. You create a class NetworkIdlingResource that wraps the OkHttp Dispatcher. In enqueue, you increment the counter; in the response callback, you decrement and invoke the stored ResourceCallback if the count hits zero. In your test class, you instantiate this resource, register it in @Before, perform the Espresso click that triggers the call, and then assert on the UI. In @After you unregister it. This keeps the test deterministic and avoids sleeping for 2000 milliseconds.

Source: developer.android.com

Read the original → developer.android.com

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.