Android: Writing test cases for Fragments

26,012

Solution 1

AndroidX provides a library, FragmentScenario, to create fragments and change their state.

app/build.gradle

dependencies {
    def fragment_version = "1.0.0"
    // ...
    debugImplementation 'androidx.fragment:fragment-testing:$fragment_version'
}

example

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        // The "fragmentArgs" and "factory" arguments are optional.
        val fragmentArgs = Bundle().apply {
            putInt("selectedListItem", 0)
        }
        val factory = MyFragmentFactory()
        val scenario = launchFragmentInContainer<MyFragment>(
                fragmentArgs, factory)
        onView(withId(R.id.text)).check(matches(withText("Hello World!")))
    }
}

More at official docs.

Solution 2

Here's a rough guide using ActivityInstrumentationTestCase2:

Step 1. Create a blank Activity to hold your fragment(s)

  private static class FragmentUtilActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      LinearLayout view = new LinearLayout(this);
      view.setId(1);

      setContentView(view);
    }
  }

Step 2: Inside your test, instantiate your fragment and add it to the blank activity

public class MyFragmentTest extends ActivityInstrumentationTestCase2<FragmentUtilActivity> { 
    private MyFragment fragment;

    @Before
    public void setup() {
        fragment = new MyFragment();
        getActivity().getFragmentManager().beginTransaction().add(1, fragment, null).commit();
    }
}

Step 3 Test your instantiated fragment

@Test
public void aTest() {
    fragment.getView().findViewById(...);
}

If you're using robolectric, this is pretty straightforward using the FragmentUtilTest class:

@Test
public void aTest() {
    // instantiate your fragment
    MyFragment fragment = new MyFragment();

    // Add it to a blank activity
    FragmentTestUtil.startVisibleFragment(fragment);

    // ... call getView().findViewById() on your fragment
}

Solution 3

Here is my working solution:

  1. Create an instrumentation unit test class for this in androidTest directory, i.e.:

    public class FragmentTest extends 
    ActivityInstrumentationTestCase2<MainActivity> {
         private MainActivity testingActivity;
         private TestFragment testFragment;
         //... 
    }
    
  2. call this constructor inside this new class:

    public FragmentTest() {
    
        super(MainActivity.class);
    }
    
  3. override the setUp() method (be sure to have R.id.fragmentContainer in your Activity class) where you will call at the end waitForIdleSync():

    @Override
    protected void setUp() throws Exception {
        super.setUp();
    
        // Starts the activity under test using
        // the default Intent with:
        // action = {@link Intent#ACTION_MAIN}
        // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
        // All other fields are null or empty.
        testingActivity = getActivity();
    
        testFragment = new TestFragment();
        testingActivity.getFragmentManager().beginTransaction().add(R.id.fragmentContainer,testFragment,null).commit();
        /**
         * Synchronously wait for the application to be idle.  Can not be called
         * from the main application thread -- use {@link #start} to execute
         * instrumentation in its own thread.
         *
         * Without waitForIdleSync(); our test would have nulls in fragment references.
         */
        getInstrumentation().waitForIdleSync();
    }
    
  4. Write a test method, for example somethng like:

    public void testGameFragmentsTextViews() {
    
       String empty = "";
       TextView textView = (TextView)testFragment.getView().findViewById(R.id.myTextView);
       assertTrue("Empty stuff",(textView.getText().equals(empty)));   
    }
    
  5. Run the test.

Solution 4

Use your main activity as the test activity that you send to ActivityInstrumentationTestCase2. Then you can work with the fragments through the fragment manager of your main activity that launches the fragments. This is even better than having a test activity because it uses the logic that you write in your main activity to test scenarios, which gives a fuller and more complete test.

Example:

public class YourFragmentTest extends ActivityInstrumentationTestCase2<MainActivity> {  
    public YourFragmentTest(){
            super(MainActivity.class);
        }

}
Share:
26,012
AnswerDroid
Author by

AnswerDroid

Gaurav Dubey =&gt; Stackoverflow is my development companion - Whenever I am struck on some issues, it comes to the rescue. Whenever I have some free time, I like to help people or solve their problems from whatever experience I've !

Updated on September 17, 2020

Comments

  • AnswerDroid
    AnswerDroid over 3 years

    In my previous projects I've done most of the work through Activities and used ActivityInstrumentationTestCase2 as per the document:
    http://developer.android.com/tools/testing/activity_testing.html
    I have an idea how to work with Activity Test cases; but when it comes to Fragment ,I don't have much idea nor found much documents related to that. So how to write test cases when I have several fragments with one or two actvities? Any example code or sample would be more helpful.

  • AnswerDroid
    AnswerDroid almost 9 years
    In android studio ; it automatically creates a test package.However it is not allowing me to add an activity inside that package. Any idea?
  • AnswerDroid
    AnswerDroid almost 9 years
    this looks interesting.. I will check it and let you know
  • AnswerDroid
    AnswerDroid almost 9 years
    getActivity().getSupportFragmentManager().beginTransaction()‌​. replace(R.id.fragment,new LoginFragment(),"LOGIN") .commit(); I am doing this . .Then I wish to test LoginFragment.How to acheive?
  • melkoth
    melkoth almost 9 years
    Can you provide more details? What are you trying to test? This is where you should be doing your basic unit testing - look here: http://developer.android.com/tools/testing/what_to_test.html for more ideas of what to test.
  • ThomasW
    ThomasW almost 8 years
    To test support-v4 Fragments, use SupportFragmentTestUtil.startVisibleFragment().
  • Siavash Abdoli
    Siavash Abdoli over 7 years
    how to handle this when fragment depends on its activity and the activity itself run fragment from pager?
  • Nachi
    Nachi over 7 years
    @SiavashA: this depends on what you are trying to test. If you want to test just the fragment, you should encapsulate all functionality within the fragment and mock/stub any external dependencies. Alternatively you can also directly write tests for your Activity if it is too closely-coupled with the Fragment. Feel free to write a new question if you have more specific questions.
  • Lassie
    Lassie over 6 years
    How to perform this by using instrumentation test for fragment onView(withId(R.id.txt_first_num_add)) .perform(typeText("6"));
  • Adi
    Adi over 5 years
    @AnswerDroid Activity does not to be added inside the test package , you have to add in java package only ,As activity classname doesn't have Test keyword in it .
  • AnswerDroid
    AnswerDroid over 4 years
    Have you tried this @Levon Petrosyan. I have accepted this as answer though.