Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to use IdlingResource in Espresso Android

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?

like image 546
Lanitka Avatar asked Aug 14 '15 14:08

Lanitka


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

like image 181
vaughandroid Avatar answered Oct 07 '22 01:10

vaughandroid


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 && callback != null) {
        callback.onTransitionToIdle();
    }
    return idle;
} 
like image 21
phq Avatar answered Oct 07 '22 01:10

phq