Home » Android » unit testing – Android: Writing test cases for Fragments

unit testing – Android: Writing test cases for Fragments

Posted by: admin April 23, 2020 Leave a comment

Questions:

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.

How to&Answers:

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.

Answer:

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
}

Answer:

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.

Answer:

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);
        }

}

Answer:

Right now ActivityInstrumentationTestCase2 is deprecated. Now you can use rules in order to use activities within your tests: http://wiebe-elsinga.com/blog/whats-new-in-android-testing/

In order for those to work you’ll have to add the dependencies to you build.gradle:

testCompile 'com.android.support.test:rules:0.5'
testCompile 'com.android.support.test:runner:0.5'

(See Why cannot I import AndroidJUnit4 and ActivityTestRule into my unit test class?)