How to test a Fragment using Espresso
Solution 1
I will do in following way Create a ViewAction as follows:
public static ViewAction doTaskInUIThread(final Runnable r) {
return new ViewAction() {
@Override
public Matcher<View> getConstraints() {
return isRoot();
}
@Override
public String getDescription() {
return null;
}
@Override
public void perform(UiController uiController, View view) {
r.run();
}
};
}
Then use below to launch code which should be run in UI Thread
onView(isRoot()).perform(doTaskInUIThread(new Runnable() {
@Override
public void run() {
//Code to add your fragment or anytask that you want to do from UI Thread
}
}));
below is an example of test case adding fragment view hierarchy
@Test
public void testSelectionOfTagsAndOpenOtherPage() throws Exception{
Runnable r = new Runnable() {
@Override
public void run() {
//Task that need to be done in UI Thread (below I am adding a fragment)
}
};
onView(isRoot()).perform(doTaskInUIThread(r));
}
Solution 2
public class VoiceFullScreenTest {
@Rule
public ActivityTestRule activityRule = new ActivityTestRule<>(
TestActivity.class);
@Test
public void fragment_can_be_instantiated() {
activityRule.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
VoiceFragment voiceFragment = startVoiceFragment();
}
});
// Then use Espresso to test the Fragment
onView(withId(R.id.iv_record_image)).check(matches(isDisplayed()));
}
private VoiceFragment startVoiceFragment() {
TestActivity activity = (TestActivity) activityRule.getActivity();
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
VoiceFragment voiceFragment = new VoiceFragment();
transaction.add(voiceFragment, "voiceFragment");
transaction.commit();
return voiceFragment;
}
}
You can start your fragment from UI thread as mentioned above.
Solution 3
You can use the androidx.fragment:fragment-testing
library. Launching the fragment in your test method is as simple as:
val fragmentArgs = Bundle()
androidx.fragment.app.testing.launchFragmentInContainer<MyFragment>(fragmentArgs)
You can find more information about this library here.
Solution 4
You can use FragmentTestRule.
Instead of the regular ActivityTestRule
you must use:
@Rule
public FragmentTestRule<?, FragmentWithoutActivityDependency> fragmentTestRule =
FragmentTestRule.create(FragmentWithoutActivityDependency.class);
You can find more details in this blog post.
Solution 5
You've probably forgot to inject the fragment in the view hierarchy. Try defining the holder container for your fragment in the TestActivity
layout (like a FrameLayout
with id fragment_container
) and then instead of just add(myFragment, "tag")
, use the add(R.id.fragment_container, myFragment, "tag")
(this method). I guess you could use the replace
method with the same signature as well.
greenrobo
Updated on July 14, 2022Comments
-
greenrobo almost 2 years
I have an Android fragment that I want to test. I created a test activity to which I add this fragment and run some Espresso tests.
However, Espresso does not find any of the views inside the fragment. It dumps the view hierarchy and it is all empty.
I do not want to use the actual parent activity. I want to just test this fragment in isolation. Has anyone done this? Is there a sample that has a similar code?
@RunWith(AndroidJUnit4.class) class MyFragmentTest { @Rule public ActivityTestRule activityRule = new ActivityTestRule<>( TestActivity.class); @Test public void testView() { MyFragment myFragment = startMyFragment(); myFragment.onEvent(new MyEvent()); // MyFragment has a recyclerview. //OnEvent is EventBus callback that in this test contains no data. //I want the fragment to display empty list text and hide the recyclerView onView(withId(R.id.my_empty_text)).check(matches(isDisplayed())); onView(withId(R.id.my_recycler)).check(doesNotExist())); } private MyFragment startMyFragment() { FragmentActivity activity = (FragmentActivity) activityRule.getActivity(); FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction(); MyFragment myFragment = new MyFragment(); transaction.add(myFragment, "myfrag"); transaction.commit(); return myFragment; } }
-
greenrobo about 8 yearsI tried this method (using add(id, fragment, tag)) but that did not help. I suspect that this is because of multiple threads interacting. Espresso somehow does not like this.