[dev-hilt] How test Fragment which configures its Toolbar with NavigationUI
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.
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.