grrrrrr
grrrrrr

Reputation: 1425

Why is IdlingResource null in Espresso tests on Android API 22?

EDIT: I've tested the below on two devices on Android API 22 and one on API 19, the one on API 19 does not have the issue. Any ideas what the difference could be between versions?

I am setting up espresso tests for my Android with an IdlingResource identical to the example here.

My Test setup:

@Rule
public ActivityTestRule<MainActivity> mMainActivity =
        new ActivityTestRule(MainActivity.class);

private IdlingResource mIdlingResource;

@Before
public void registerIdlingResource() {
    mIdlingResource = mMainActivity.getActivity().getIdlingResource();
    IdlingRegistry.getInstance().register(mIdlingResource);
}

In my Activity each time I change the Idle state I call:

if (mIdlingResource != null) {
    mIdlingResource.setIdleState(false);
} else {
    Log.d("error ", "idle resource is null");
}

My issue comes when trying to change the idle state in my activity -- there seems to be a lag between when the activity is created and the IdlingResource is available.

In the first test of the sequence, the IdlingResource is never available -- as such I cannot set the initialValue of the IdlingResource to false and then later switch back to true. That seems to be caused by the annotation lifecycle as described in this article:

enter image description here

From what I can tell the Activity is created by the @Rule and then the IdlingResource is instantiated in the @Before. Since the Activity is already running the idle resource is null at each of the points where I attempt to change the state.

In subsequent tests only the first instance of setIdleState (which occurs in the onCreate) is skipped -- perhaps something to do with the Activity lifecycle with the @Rule? -- but the others operate as expected.

Is there a best practice to getting the @Rule and @Before to work in order before the first test?

Upvotes: 1

Views: 962

Answers (2)

grrrrrr
grrrrrr

Reputation: 1425

The best solution to this issue of the activity launching before the IdlingResource is available is to set the Rule so that it does not launch the activity. The benefit of this method is that you do not have to manually register the IdlingResource in the Activity.

To make implement this solution, use the following constructor of ActivityTestRule

ActivityTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity)

So the code would look like:

@Rule
public ActivityTestRule<MainActivity> mMainActivity =
        new ActivityTestRule(MainActivity.class, false, true);

private IdlingResource mIdlingResource;

@Before
public void registerIdlingResource() {
    mIdlingResource = mMainActivity.getActivity().getIdlingResource();
    IdlingRegistry.getInstance().register(mIdlingResource);
    mMainActivity.launchActivity(new Intent());
}

Upvotes: 1

Sanchita Santra
Sanchita Santra

Reputation: 359

You can use a static IdlingResource in your activity. Initialize the mIdlingResource before starting background tasks (I'm not including the code for initialization since you have already written it).

private static IdlingResource mIdlingResource;

//Getter for mIdlingResource
public IdlingResource getmIdlingResource() {
    return mIdlingResource;
}

Then you can access this static resource from your test instead of creating a new variable.

@Before
public void registerIdlingResource() {
    IdlingRegistry.getInstance().register(mMainActivity.getActivity().getmIdlingResource());
}

Then mIdlingResource will not be null in the Activity.

Note - Google advises the use of CountingIdlingResource. You can find the implementation here - https://developer.android.com/reference/android/support/test/espresso/idling/CountingIdlingResource

UPDATE: After checking the code in the comments.

Your IdlingResource is getting created when you're calling it for the first time while registering.

Just call getIdlingResource() once in onCreate() of your activity (or before you call setIdleState). Leave the rest of the code same. It won't create duplicates because a null check is performed before initializing.

Upvotes: 1

Related Questions