Reputation: 1425
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:
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
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
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