Correct way to use IdlingResource in Espresso Android

By : Lanitka
Source: Stackoverflow.com
Question!

I'm writing UI tests with Espresso. App cooperates tightly with server, so in many cases, I need to wait for either value to be calculated, or data is got and displayed, etc. Espresso suggests using IdlingResource for this. My IdlingResource classes look like this (simple and clear example).

public class IRViewVisible implements IdlingResource {

private View view;
private ResourceCallback callback;

public IRViewVisible(View view) {
    this.view = view;
}

@Override
public String getName() {
    return IRViewVisible.class.getName();
}

@Override
public boolean isIdleNow() {
    if(view.getVisibility() == View.VISIBLE && callback != null) {
        callback.onTransitionToIdle();
        return true;
    }
    return false;
}

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

Please correct me if I'm wrong anywhere (as sometimes it seems to me that my IdlingResources do not work properly). I register the idling resource in setUp() like this:

IRViewVisible ir = new IRViewVisible(View v);
Espresso.registerIdlingResources(ir).

Unregister it on tearDown().

I found this article (there is a section called "Register a component tied to an Activity instance") — I do not use his schema, but I checked hashcode of view that was set to IdlingResource after registering (in each method), and it's not the same view — all hashes are different.

Another question: One Test class (it's results) can't have any effect on another Test class, can it?

By : Lanitka


Answers

I'm guessing your problem stems from getName() returning the same name for all instances of IRViewVisible. This means you can only have one registered instance of it at a time - any subsequent registrations will fail (silently!).

You mention that you clear the IdlingResources at the end of each test, but if you are register multiple instances of it at once, you need to make sure each instance has a unique name. it's not clear from your question if you're registering multiple instances of IRViewVisible in a single test.

As to your final question: Yes, it is possible. Android doesn't completely shut down the Application between test runs - just the Activities. Common things which can cause problems:

  • Failing to clear persistent state (saved data).
  • Failing to clear global state - e.g. static variables/singletons
  • Not waiting for background threads to finish running.

As an aside, it's worth noting that you only call onTransitionToIdle() inside isIdleNow(). This works (thanks @Be_Negative for the heads up!) but it could slow down your tests a lot, since Espresso will only poll isIdleNow() every few seconds. If you call onTransitionToIdle() as soon as the view becomes visible, it should speed things up considerably.

I needed something similar to your IRViewVisible myself, here's my effort.



Well, first of all you shouldn't need to use Espresso IdlingResource to test server calls. If you use AsyncTasks in your server calls, Espresso will be able to know when to be idle and when not. If this is not enough: try to refactor your code in this way:

  IRViewVisible idlingResource = new IRViewVisible(yourView);
  IdlingPolicies.setMasterPolicyTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);
        IdlingPolicies.setIdlingResourceTimeout(waitingTime * 2, TimeUnit.MILLISECONDS);

        // Now we wait
        Espresso.registerIdlingResources(idlingResource);

        // Stop and verify


        // Clean up
        Espresso.unregisterIdlingResources(idlingResource);

Hope to be helpful.



So the isIdleNow() method will never return true if you don't set a callback to the idlingResource? I reckon it's better to refactor it like this:

@Override
public boolean isIdleNow() {
    boolean idle = view.getVisibility() == View.VISIBLE;
    if(idle 
By : phq


This video can help you solving your question :)
By: admin