How can I test fragments with Robolectric?

AndroidRobolectric

Android Problem Overview


I know there is a Robolectric.shadowOf(Fragment) method and a ShadowFragment class, thought they aren't listed on the docs, but I can't make it work.

myFragment = new MyFragment();
myFragment.onCreateView(LayoutInflater.from(activity), (ViewGroup) activity.findViewById(R.id.container), null);
myFragment.onAttach(activity);
myFragment.onActivityCreated(null); 

I'm working with API level 13 (Honeycomb).

Thanks.

Android Solutions


Solution 1 - Android

Edit #4 & #5: In Robolectric 3.*, they split up the fragment starting functions.

For support fragments, you will need to add a dependency to your build.gradle:

testCompile "org.robolectric:shadows-supportv4:3.8"

Import: org.robolectric.shadows.support.v4.SupportFragmentTestUtil.startFragment;

For platform fragments, you don't need this dependency. Import: import static org.robolectric.util.FragmentTestUtil.startFragment;

They both use the same name of startFragment().

import static org.robolectric.shadows.support.v4.SupportFragmentTestUtil.startFragment;

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class)
public class YourFragmentTest
{
    @Test
    public void shouldNotBeNull() throws Exception
    {
        YourFragment fragment = YourFragment.newInstance();
        startFragment( fragment );
        assertNotNull( fragment );
    }
}

Edit #3: Robolectric 2.4 has an API for support and regular fragments. You can either use the newInstance() pattern or use the constructor when constructing your Fragment's.

import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertNotNull;
import static org.robolectric.util.FragmentTestUtil.startFragment;

@RunWith(RobolectricGradleTestRunner.class)
public class YourFragmentTest
{
    @Test
    public void shouldNotBeNull() throws Exception
    {
        YourFragment fragment = new YourFragment();
        startFragment( fragment );
        assertNotNull( fragment );
    }
}

Edit #2: There's a new helper if you're using support fragments (one that supports regular activities/fragments should be in the next release):

import static org.robolectric.util.FragmentTestUtil.startFragment;

@Before
public void setUp() throws Exception
{
    fragment = YourFragment.newInstance();
    startFragment( fragment );
}

Edit: If you upgraded to Robolectric 2.0:

public static void startFragment( Fragment fragment )
{
    FragmentActivity activity = Robolectric.buildActivity( FragmentActivity.class )
                                           .create()
                                           .start()
                                           .resume()
                                           .get();

    FragmentManager fragmentManager = activity.getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
    fragmentTransaction.add( fragment, null );
    fragmentTransaction.commit();
}

Original answer

As the other commenter suggested, you do need to use the fragment manager (instead of calling the lifecycle methods you listed above).

@RunWith(MyTestRunner.class)
public class YourFragmentTest
{
    @Test
    public void shouldNotBeNull() throws Exception
    {
        YourFragment yourFragment = new YourFragment();
        startFragment( yourFragment );
        assertNotNull( yourFragment );
    }

I create a test runner and have a function that starts up a fragment for me so I can use it everywhere.

public class MyTestRunner extends RobolectricTestRunner
{
    public MyTestRunner( Class<?> testClass ) throws InitializationError
    {
        super( testClass );
    }

    public static void startFragment( Fragment fragment )
    {
        FragmentManager fragmentManager = new FragmentActivity().getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add( fragment, null );
        fragmentTransaction.commit();
    }
}

Solution 2 - Android

You guys are all doing this the hard way. Just use FragmentTestUtil.

FragmentTestUtil.startFragment(yourfragment);

Solution 3 - Android

Support fragments have been moved to module:

> shadows-support-v4

(as of July,2015, Robolectric v3.0)

Add a gradle dependency to app/build.gradle:

testCompile 'org.robolectric:shadows-support-v4:3.0'

Then import to your Robolectric test java class:

import org.robolectric.shadows.support.v4.SupportFragmentTestUtil;

Then you can start & use a support-v4 fragment for testing:

@Test
public void minimalFragmentTest() throws Exception {
    MyFunFragment fragment = new MyFunFragment();
    SupportFragmentTestUtil.startVisibleFragment(fragment);
    assertThat(fragment.getView()).isNotNull();
}

References:

Solution 4 - Android

I'm pretty sure you have to create a FragmentTransaction using the FragmentManager, then it will work.

Solution 5 - Android

I just wanted to add that in Robolectric 2.0 even after doing:

activity = Robolectric.buildActivity(FragmentActivity.class).create().start().resume().get();
fragment.show(activity.getSupportFragmentManager(), null);
fragment.getDialog();  //This stills returns null

It still returned null for me. what I did was to add activity.getSupportFragmentManager().executePendingTransaction(); and it worked.

It seems robolectric doesn't run this for some reason. it seems that maybe the Looper is paused or something. any way this worked for me and it looks like this:

activity = Robolectric.buildActivity(FragmentActivity.class).create().start().resume().get();
fragment.show(activity.getSupportFragmentManager(), null);
activity.getSupportFragmentManager().executePendingTransactions();
fragment.getDialog();

Solution 6 - Android

Old android fragments are already deprecated, seems like support fragments soon will be deprecated too. To test androidx fragments you can use fragment scenarios with robolectric https://developer.android.com/training/basics/fragments/testing

testImplementation 'androidx.fragment:fragment-testing:1.2.2'
val scenario = launchFragmentInContainer<MyFragment>()
scenario.onFragment { fragment ->
    assertNotNull(fragment.view.synteticInflatedView)
}

Solution 7 - Android

SupportFragmentTestUtil.startFragment(fragment, AppCompatActivity::class.java)

If the activity is extending AppCompatActivity

This is using Kotlin

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkanedaView Question on Stackoverflow
Solution 1 - AndroidcolabugView Answer on Stackoverflow
Solution 2 - AndroidBrian GriffeyView Answer on Stackoverflow
Solution 3 - AndroidBakerView Answer on Stackoverflow
Solution 4 - AndroidChristopher PerryView Answer on Stackoverflow
Solution 5 - AndroidsuperjugyView Answer on Stackoverflow
Solution 6 - AndroidLink182View Answer on Stackoverflow
Solution 7 - AndroidprijupaulView Answer on Stackoverflow