11 April 2024 Leave a comment Tech-Help
Endless scrolling is a common feature in modern applications, allowing users to continuously scroll through a list of items without interruption. When implementing this in a RecyclerView with RxJava, it’s crucial to ensure that the UI behaves as expected. This guide will walk you through the process of testing endless scrolling using Espresso, a powerful tool for writing concise, reliable Android UI tests.
Understanding the Testing Challenge
The challenge lies in simulating the loading of new data as the user scrolls and ensuring the progress indicator is displayed correctly. The test involves scrolling down to the last item in the RecyclerView and checking if the progress item becomes visible.
Setting Up Your Test
Begin by generating test data correctly. Ensure that each item in the test data has a unique timestamp. This will prevent the progress item from being confused with a regular list item during testing.
private static InstaItem makeInstaItem(String prefix, int i, int dateCoefficient) {
InstaItem item = new InstaItem();
item.setLocation(new Location(prefix + "_location_" + i));
item.setCreatedTime((i + 1) * 1000000L * dateCoefficient);
item.setImages(makeInstaImages());
item.setId(randomUuid());
return item;
}
In your presenter logic, ensure that new items are added when more data is fetched. This can be done by updating the subscription logic to display the new feed items.
subscribe(items -> {
if (!items.isEmpty()) {
getMvpView().showFeed(items);
}
Timber.d("load more - items fetched");
});
Writing the Espresso Test
You don’t need to simulate a delay for the Observable. Keep the implementation straightforward by observing on the main thread and proceeding with the UI actions.
when(mockDataManager.getOldFeedItemsFromServer()).thenReturn(Observable.just(oldFeed.getInstaItems())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(x -> {
Timber.d("On next after delay");
when(mockDataManager.subscribeOnFeedItemsChanges())
.thenReturn(Observable.just(oldFeed.getInstaItems()));
}));
instaActivityActivityTestRule.launchActivity(null);
int position = 0;
for (InstaItem item : feed.getInstaItems()) {
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.scrollToPosition(position));
onView(withText(item.getLocation().getName()))
.check(matches(isDisplayed()));
onView(withText(InstaAdapter.dateFormat.format(new Date(item.getCreatedTime() * 1000))))
.check(matches(isDisplayed()));
position++;
}
for (InstaItem item : oldFeed.getInstaItems()) {
onView(withId(R.id.recycler_view))
.perform(RecyclerViewActions.scrollToPosition(position));
onView(withText(item.getLocation().getName()))
.check(matches(isDisplayed()));
onView(withText(InstaAdapter.dateFormat.format(new Date(item.getCreatedTime() * 1000))))
.check(matches(isDisplayed()));
position++;
}
By following these steps, you should be able to smoothly test the endless scrolling functionality of your RecyclerView, ensuring that the progress bar is displayed appropriately as new items are loaded.
Final Thoughts
Although UI testing can be challenging, it is a critical part of the development process. However, for testing presenter logic, consider unit tests as they can be more straightforward and less time-consuming than UI tests.