architecture-samples icon indicating copy to clipboard operation
architecture-samples copied to clipboard

[dev-hilt] How test Fragment which configures its Toolbar with NavigationUI

Open ibrahimyilmaz opened this issue 5 years ago • 1 comments

We are able provide NavHostController to FragmentScenario for the Fragments which configures Toolbar by using NavController.

We have HiltExt.kt workaround instead of FragmentScenario at the moment and it does not support this. So, we need to provide NavHostController order to be able test the fragments which configure its Toolbar by using NavController.

https://developer.android.com/guide/navigation/navigation-testing#test_fragment_navigation

val scenario = launchFragmentInContainer {
    TitleScreen().also { fragment ->

        // In addition to returning a new instance of our Fragment,
        // get a callback whenever the fragment’s view is created
        // or destroyed so that we can set the NavController
        fragment.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
            if (viewLifecycleOwner != null) {
                // The fragment’s view has just been created
                Navigation.setViewNavController(fragment.requireView(), navController)
            }
        }
    }
}

HiltExt.kt may cover this.

ibrahimyilmaz avatar Jul 22 '20 18:07 ibrahimyilmaz

Recommended Solution Use launchFragmentInHiltContainer (custom version) that gives you control over the NavController.

Step 1: Create a reusable launchFragmentInHiltContainer function

inline fun <reified T : Fragment> launchFragmentInHiltContainer( navController: NavController? = null, fragmentArgs: Bundle? = null, crossinline action: T.() -> Unit = {} ) { val startActivityIntent = Intent.makeMainActivity( ComponentName( ApplicationProvider.getApplicationContext(), HiltTestActivity::class.java ) )

ActivityScenario.launch<HiltTestActivity>(startActivityIntent).onActivity { activity ->
    val fragment = activity.supportFragmentManager.fragmentFactory
        .instantiate(requireNotNull(T::class.java.classLoader), T::class.java.name)
    fragment.arguments = fragmentArgs
    activity.supportFragmentManager.beginTransaction()
        .add(android.R.id.content, fragment, "")
        .commitNow()

    navController?.let { controller ->
        fragment.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
            if (viewLifecycleOwner != null) {
                Navigation.setViewNavController(fragment.requireView(), controller)
            }
        }
    }

    (fragment as T).action()
}

} Make sure you have a simple HiltTestActivity defined:

@AndroidEntryPoint class HiltTestActivity : AppCompatActivity() Step 2: Use it in your test

@Test fun testToolbarSetupWithNavController() { val mockNavController = mock(NavController::class.java)

launchFragmentInHiltContainer<MyFragment>(navController = mockNavController) {
    // Optionally verify toolbar setup
    assertNotNull(requireActivity().findViewById<Toolbar>(R.id.toolbar))
}

} Benefits Keeps your test clean and composable.

Works with Hilt DI.

Allows NavigationUI.setupWithNavController(toolbar, navController) to be tested.

Solves the issue where HiltExt.kt doesn’t let you inject a NavController.

VaradGupta23 avatar Jul 21 '25 06:07 VaradGupta23