Android Espresso does not have a NavController set Error

[亡魂溺海] 提交于 2020-07-23 06:52:16

问题


I am trying to test a fragment in my navigation architecture and my test is as follows:

test.kt

@RunWith(AndroidJUnit4::class)
@MediumTest
internal class AddingAccountTest{

@get:Rule
var activityRule: ActivityTestRule<MainActivity>
        = ActivityTestRule(MainActivity::class.java)

@Before fun loadCorrespondingFragment(){

}

@Test fun checkThatAllFieldsInFormAreEmpty(){
    // Create a TestNavHostController
    val navController = TestNavHostController(ApplicationProvider.getApplicationContext())
    navController.setGraph(R.navigation.navigation_drawer_main)

    // Create a graphical FragmentScenario for the TitleScreen
    val titleScenario = launchFragmentInContainer<AddAccountFragment>(Bundle(), themeResId = R.style.Locky_Theme)

    // Set the NavController property on the fragment
    titleScenario.onFragment { fragment ->
        Navigation.setViewNavController(fragment.requireView(), navController)
    }
    onView(withId(R.id.Account_Name)).check(matches(isEnabled()))
}
}

But when i run it, i am getting the follow errors:

java.lang.IllegalStateException: View androidx.constraintlayout.widget.ConstraintLayout{65be158 V.E...... ......I. 0,0-0,0 #7f0a0129 app:id/cl_layout} does not have a NavController set
at androidx.navigation.Navigation.findNavController(Navigation.java:84)
at androidx.navigation.fragment.NavHostFragment.findNavController(NavHostFragment.java:118)
at androidx.navigation.fragment.FragmentKt.findNavController(Fragment.kt:29)
at com.th3pl4gu3.locky_offline.ui.main.add.account.AddAccountFragment.observeBackStackEntryForLogoResult(AddAccountFragment.kt:89)
at com.th3pl4gu3.locky_offline.ui.main.add.account.AddAccountFragment.onViewCreated(AddAccountFragment.kt:72)

The error is occurring in my AddAccountFragment.kt on line 89 which contains this code:

AccountFragment.kt

val navBackStackEntry = findNavController().getBackStackEntry(R.id.Fragment_Add_Account)

This code is used to get backstack entry data as follows:

private fun observeBackStackEntryForLogoResult() {
    // After a configuration change or process death, the currentBackStackEntry
    // points to the dialog destination, so you must use getBackStackEntry()
    // with the specific ID of your destination to ensure we always
    // get the right NavBackStackEntry
    val navBackStackEntry = findNavController().getBackStackEntry(R.id.Fragment_Add_Account)

    // Create our observer and add it to the NavBackStackEntry's lifecycle
    val observer = LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_RESUME
            && navBackStackEntry.savedStateHandle.contains(KEY_ACCOUNT_LOGO)
        ) {
            /*
            * Update the logo
            */
            viewModel.logoUrl =
                navBackStackEntry.savedStateHandle.get<String>(KEY_ACCOUNT_LOGO)!!

            navBackStackEntry.savedStateHandle.remove<AccountSort>(KEY_ACCOUNT_LOGO)
        }
    }
    navBackStackEntry.lifecycle.addObserver(observer)

    // As addObserver() does not automatically remove the observer, we
    // call removeObserver() manually when the view lifecycle is destroyed
    viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
        if (event == Lifecycle.Event.ON_DESTROY) {
            navBackStackEntry.lifecycle.removeObserver(observer)
        }
    })
}

Can someone help me on why this error is occurring ?


回答1:


titleScenario.onFragment { fragment ->
    Navigation.setViewNavController(fragment.requireView(), navController)
}

onFragment is called after the fragment has moved to the resumed state. It's too late as you are using NavController in onCreateView (according to the stack trace you posted).

To fix this problem, you need to set the TestNavHostController way sooner, just after fragment's view has been created:

val titleScenario = launchFragmentInContainer<AddAccountFragment>(
    Bundle(),
    themeResId = R.style.Locky_Theme
).also { fragment ->
    fragment.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
        if (viewLifecycleOwner != null) {
            Navigation.setViewNavController(fragment.requireView(), navController)
        }
    }
}

To learn more, visit Test Navigation guide.



来源:https://stackoverflow.com/questions/62515314/android-espresso-does-not-have-a-navcontroller-set-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!