Migrate a Robolectric test to FragmentScenario
This blog post describes my experiences migrating a unit test from Robolectric ‘old’ API to the new AndroidX FragmentScenario API. I wanted to do that as part of experimenting this new API, which brings some advantages over the old method (see http://robolectric.org/androidx_test/).
My previous approach usually involved setting up the parent activity and then simulating all the steps until the Fragment under test was visible in that activity — which was not trivial, because it involved setting up the test dependencies for both the Fragment and parent activity.
As an example:
performQuery
, progressBar
and shouldBeVisible
, use the standard View methods to assert stuff — mostly View#findViewById
and View#getVisibility
Moving on, the new FragmentScenario API from AndroidX allows developers to test a given Fragment in isolation of the parent activity. Plus, it provides methods to drive the Fragment’s lifecycle states for testing.
As a curiosity, under-the-hood this API will also declare and setup an ‘EmptyActivity’ and inject the Fragment into it. That’s why the documentation mentions the dependency should be included as debugImplementation
(typically we would use testImplementation for test dependencies).
One consequence of testing the Fragment in isolation is that you can no longer have hard dependencies to the parent activity. For example, I usually casted my Activity at Fragment#onAttach:
// On the Fragmentoverride fun onAttach(context: Context) {
super.onAttach(context)
if (context is ParentActivity) {
parentActivity = context
} else {
throw Exception("$context must implement ParentActivity")
}
}
override fun onDetach() {
super.onDetach()
parentActivity = null
}
Where now a recommended approach is to set the ParentActivity
through your Activity#onAttachFragment callback:
// On the Activityoverride fun onAttachFragment(@NonNull fragment: Fragment) {
if (fragment is SearchFragment) {
fragment.setParentActivity(this)
}
}
Moving on, in order to test the fragment you have to launch it using one of the available launch*
methods and assert stuff using either the #onFragment callback or using Espresso view matchers.
Here’s the same test migrated to the FragmentScenario API:
According to the documentation, calling FragmentScenario#onFragment synchronously waits for the application to be idle and provides a reference to the Fragment that makes it easy to make assertions on your views.
Note: If you have custom views, you might want to specify a theme when setting up the FragmentScenario, otherwise it will complain that it cannot find a given resource.
And that’s it! Even though the fragment-testing library is still in alpha, I did not find any issues along the way. It was easy to use and seems to provide a safer way of running tests. I will most likely begin to use it next time I write a new test.
I hope you found this useful, let me know your thoughts =)
And feel free to follow me on Twitter https://twitter.com/belchii