Wait in your tests with IdlingResources
I just started with Espresso, I was following this nice tutorial, Testing a sorted list with Espresso to test if the elements on a listview are sorted alphabetically. I thought it was a good idea to use it in an app I am making for learning purposes. The article is easy to follow and when I was waiting for the "All test passed" message a I got a disappointed. The list a was testing was null. Sad face :(
Of course it was null, the test runs right away after the activity starts, and the data I am using to inflate my list comes from the Internet, so if I want to test this data, the first thing I have to do is wait for the data to be downloaded.
NOTE: I am new in testing so everything I have done so far is just for learning the use of Espresso, so probably test if the order is shown alphabetically is something that you won't do directly in the activity, and checking if the data is synced is probably better to do it in the thread that handles the downloads and not in the activity itself.
The best explanation is in the Android Documentation ...test authors can register the custom resource and Espresso will wait for the resource to become idle prior to executing a view operation.
So it is a resource like an activity or a service, that the test will wait to be run, until some condition to happened.
This will be the basic structure for our test. If you need more info just check the article above mentioned:Testing a sorted list with Espresso
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityTest {
@Rule
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class);
@Test
public void testToBeRunAfterSync() {
//...
}
}
If we use this template, testToBeRunAfterSync()
will be run as soon as the activity is visible. We want to wait until we have data in the activity, so we need to tell the test to wait for that.
We will create a class that implements the IdlingResource
interface. Here we will say when our resource (MainActivity) is idle (ready to be tested). This will be done in isIdleNow()
create the logic you need to know when it happens. In this case I have a parameter in MainActivity
that is set to true when the data is synced. I access it via activity.isSyncFinished()
public class MainActivityIdlingResource implements IdlingResource {
private MainActivity activity;
private ResourceCallback callback;
public MainActivityIdlingResource(MainActivity activity) {
this.activity = activity;
}
@Override
public String getName() {
return "MainActivityIdleName";
}
@Override
public boolean isIdleNow() {
Boolean idle = isIdle();
if (idle) callback.onTransitionToIdle();
return idle;
}
public boolean isIdle() {
return activity != null && callback != null && activity.isSyncFinished();
}
@Override
public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
this.callback = resourceCallback;
}
}
At this point we need to add the register and unregister methods to our test class.
@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityTest {
private MainActivityIdlingResource idlingResource;
@Rule
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class);
@Before
public void registerIntentServiceIdlingResource() {
MainActivity activity = activityTestRule.getActivity();
idlingResource = new MainActivityIdlingResource(activity);
Espresso.registerIdlingResources(idlingResource);
}
@After
public void unregisterIntentServiceIdlingResource() {
Espresso.unregisterIdlingResources(idlingResource);
}
@Test
public void testToBeRunAfterSync() {
//...
}
}
Now the test testToBeRunAfterSync()
will be run after we call callback.onTransitionToIdle()
on the MainActivityIdlingResource
Implementing IdlingResource
allows us to be in charge of when the tests run, so we have the control on what and how to wait for before we run them. This is particularly helpful when our application does some tasks that take long times before it is testable, as getting data from cloud sources.
This is more a snippet as a explanation of how the idlingResource
works. For more detailed information read the Android Documetatation and this two articles that covers this topic in more detail.
Chiu-Ki Chan @ Square Island: Espresso: Custom Idling Resource
Stefano Dacchille @ Jimbo Blog: Wait for it...a deep dive into Espresso's Idling Resources