Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test condition for findFragmentByTag

Android Studio 3.2 Canary 2
Build #AI-173.4591728, built on February 8, 2018
JRE: 1.8.0_152-release-1024-b01 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Linux 4.14.18-300.fc27.x86_64

I have the following activity and I want to unit test the case where the fragment is already attached and should return a non-null. And should fall into the else condition:

This is my activity:

public class BillingActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.billing_container);

        if(getSupportFragmentManager().findFragmentByTag(BillingView.TAG) == null) {
            final FragmentTransaction fragmentTransaction =
                    getSupportFragmentManager().beginTransaction();

            fragmentTransaction.add(
                    R.id.billing_view_container,
                    BillingView.newInstance(),
                    BillingView.TAG);

            fragmentTransaction.commit();
        }
        else {
            Timber.d("Fragment already attached");
        }
    }
}

The test class is this: I can write the test to attach a fragment, but I want to test the condition when a fragment is already attached and should return non-null.

class BillingActivityTest: BaseRobolectricTestRunner() {
    private lateinit var billingActivity: BillingActivity

    @Before
    fun setup() {
        billingActivity = Robolectric.buildActivity(BillingActivity::class.java)
                .create()
                .start()
                .get()
    }

    @Test
    fun testBillingActivityIsNotNullValue() {
        assertThat(billingActivity, `is`(notNullValue()))
    }

    @Test
    fun testBillingFragmentHasStarted() {
        val actualFragment = billingActivity
                .supportFragmentManager
                .findFragmentByTag(BillingView.TAG)

        assertThat(actualFragment.tag, `is`(BillingView.TAG))
    }

    @Test
    fun testBillingFragmentAlreadyAttached() {
        /* how to test */
    }
}

Thanks for any suggestions,

like image 535
ant2009 Avatar asked Feb 04 '23 01:02

ant2009


2 Answers

The approach you've chosen (using recreate()) will work as long as it replicates your requested behavior. I believe it is the shortest possible approach out there.

Nevertheless, I cannot consider it to be a pure unit test, because in fact you are cheating, because obviously you are not interested in recreate() action of the activity (which might as well come with a side effect).

If you want to perform pure unit testing, than here is the way to do that. Having declared activity as such:


    class MainActivity : AppCompatActivity() {

        internal var fragmentManagerRetriever = FragmentManagerRetriever()

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)

            val fragmentManager = fragmentManagerRetriever.getFragmentManager(this)
            if (fragmentManager.findFragmentByTag("TAG") == null) {
                val fragmentTransaction = fragmentManager.beginTransaction()
                fragmentTransaction.add(SomeFragment(), "TAG")
                fragmentTransaction.commit()
            }
        }

    }

Where FragmentManagerRetriever is as simple as this:


    class FragmentManagerRetriever {

        public FragmentManager getFragmentManager(FragmentActivity activity) {
            return activity.getSupportFragmentManager();
        }

    }

Then you have a seam to perform pure unit testing:


    @Test
    fun nullCase() {
        val activityController = Robolectric.buildActivity(MainActivity::class.java)
        val activity = activityController.get()

        val fragmentManagerRetriever = mock(FragmentManagerRetriever::class.java)
        val fragmentManager = mock(FragmentManager::class.java)
        val fragmentTransaction = mock(FragmentTransaction::class.java)
        activity.fragmentManagerRetriever = fragmentManagerRetriever

        `when`(fragmentManagerRetriever.getFragmentManager(activity)).thenReturn(fragmentManager)
        `when`(fragmentManager.findFragmentByTag("TAG")).thenReturn(null)
        `when`(fragmentManager.beginTransaction()).thenReturn(fragmentTransaction)

        activityController.create()

        val inOrder = Mockito.inOrder(fragmentTransaction)
        inOrder.verify(fragmentTransaction).add(ArgumentMatchers.any(SomeFragment::class.java), ArgumentMatchers.eq("TAG"))
        inOrder.verify(fragmentTransaction).commit()
    }

And a test for non-null case:


    @Test
    fun nonNullCase() {
        val activityController = Robolectric.buildActivity(MainActivity::class.java)
        val activity = activityController.get()

        val fragmentManagerRetriever = mock(FragmentManagerRetriever::class.java)
        val fragmentManager = mock(FragmentManager::class.java)
        val fragmentTransaction = mock(FragmentTransaction::class.java)
        activity.fragmentManagerRetriever = fragmentManagerRetriever

        `when`(fragmentManagerRetriever.getFragmentManager(activity)).thenReturn(fragmentManager)
        `when`(fragmentManager.findFragmentByTag("TAG")).thenReturn(mock(Fragment::class.java))

        activityController.create()

        verifyZeroInteractions(fragmentTransaction)
    }

like image 53
azizbekian Avatar answered Feb 06 '23 14:02

azizbekian


I managed to do like this by called the activity.recreate()

@Test
fun testBillingFragmentAlreadyAttached() {
     billingActivity.recreate()

     val actualFragment = billingActivity
            .supportFragmentManager
            .findFragmentByTag(BillingView.TAG)

     assertThat(actualFragment.tag, `is`(BillingView.TAG))
}

But if anyone has a better way. It would be good to hear about another solution.

like image 44
ant2009 Avatar answered Feb 06 '23 14:02

ant2009