Skip to content
tezvyn:

How would you implement and register a custom IdlingResource?

Source: developer.android.comHardHow cards are made

How would you implement and register a custom IdlingResource?
Summary

Whether you know Espresso's async contract.

Key points

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

Watch out for

Suggesting Thread.sleep or polling loops.

What's really being asked

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.

The full answer

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.

The mistakes people make

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.

What usually comes next

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.

A 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.

Interview question

Why must a custom IdlingResource invoke the callback given to registerIdleTransitionCallback when transitioning to idle?

  • a.To prevent the registry from leaking the resource across test suites
  • b.To notify the background thread that the UI thread is currently idle
  • c.To allow Espresso to resume immediately instead of repeatedly polling isIdleNowCorrect
  • d.To decrement the internal atomic counter back to zero automatically
Why?

Invoking the callback tells Espresso the exact moment the resource is idle so it can continue without polling; omitting it forces Espresso to busy-wait on isIdleNow. Resource leaks are prevented by unregistering in teardown, not by the callback, and the counter is decremented by your own logic rather than automatically by the callback.

Just read this? Test yourself on what you have been reading.

Read the original → developer.android.com

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on android — each one lists the topics its interview covers.

See open roles