Android UI测试与山丘和NavComponent - NavController未设置错误



我一直在尝试为Android应用程序编写一些UI测试。我遵循官方文档,youtube教程和stackoverflow答案,我一直得到相同的错误。

Caused by: java.lang.IllegalStateException: View androidx.constraintlayout.widget.ConstraintLayout{f81ae0c V.E...... ........ 0,0-1080,2006 aid=1073741835} does not have a NavController set

我尝试使用导航测试库来设置navController,我也尝试使用Mockito。我遵循谷歌的例子设置它在场景观察永远。似乎什么都没用,所以请帮忙将不胜感激。

my home fragment

@AndroidEntryPoint
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding
private val viewModel: HomeViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpOnClicks()
binding.homeLoginBtn.setOnClickListener {
val action = HomeFragmentDirections.actionHomeFragmentToLoginFragment()
view.findNavController().navigate(action)
}
}
private fun setUpOnClicks() {
binding.homeSignUpBtn.setOnClickListener {
view?.findNavController()?.navigate(R.id.loginFragment)
}
binding.homeLoginBtn.setOnClickListener {
view?.findNavController()?.navigate(R.id.loginFragment)
}
}
}

my Test class

@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
@HiltAndroidTest
class MainTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
lateinit var navController: NavController
@Before
fun init() {
hiltRule.inject()
navController = Mockito.mock(NavController::class.java)
}
@Test
fun someTest() {
//val navController = TestNavHostController(ApplicationProvider.getApplicationContext())
val scenario = launchFragmentInHiltContainer<HomeFragment>() {
HomeFragment().also { fragment ->
fragment.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
//if (viewLifecycleOwner != null) {
navController.setGraph(R.navigation.nav_graph)
Navigation.setViewNavController(fragment.requireView(), navController)
// }
}
}
}
onView(withId(R.id.home_login_btn)).check(matches(isDisplayed()))
onView(withId(R.id.home_sign_up_btn)).check(matches(isDisplayed()))
onView(withId(R.id.home_login_btn)).perform(click())
}
}

我build.gradle

def fragment_version = "1.4.1"
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation "androidx.fragment:fragment-ktx:$fragment_version"
//Navigation
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

//testing
// Hilt
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-compiler:$hilt_version"
// For instrumentation tests
androidTestImplementation  "com.google.dagger:hilt-android-testing:$hilt_version"
kaptAndroidTest "com.google.dagger:hilt-compiler:$hilt_version"
debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
def test_version = "1.4.0"
androidTestImplementation "androidx.test:core-ktx:$test_version"
testImplementation "androidx.test:core-ktx:$test_version"
implementation "androidx.test:core:$test_version"
androidTestImplementation "org.mockito:mockito-android:4.5.1"
androidTestImplementation("androidx.navigation:navigation-testing:$nav_version")

和完整错误

Caused by: java.lang.IllegalStateException: View androidx.constraintlayout.widget.ConstraintLayout{f81ae0c V.E...... ........ 0,0-1080,2006 aid=1073741835} does not have a NavController set
at androidx.navigation.Navigation.findNavController(Navigation.kt:71)
at androidx.navigation.ViewKt.findNavController(View.kt:28)
at j.app.uitestswithnav.HomeFragment.onViewCreated$lambda-0(HomeFragment.kt:40)
at j.app.uitestswithnav.HomeFragment.$r8$lambda$ZttjwAPLhhUQTJ71aRb-Z0PLw1I(Unknown Source:0)
at j.app.uitestswithnav.HomeFragment$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7455)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1131)
at android.view.View.performClickInternal(View.java:7432)
at android.view.View.access$3700(View.java:835)
at android.view.View$PerformClick.run(View.java:28810)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at androidx.test.espresso.base.Interrogator.loopAndInterrogate(Interrogator.java:14)
at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:8)
at androidx.test.espresso.base.UiControllerImpl.loopUntil(UiControllerImpl.java:1)
at androidx.test.espresso.base.UiControllerImpl.injectMotionEvent(UiControllerImpl.java:6)
at androidx.test.espresso.action.MotionEvents.sendUp(MotionEvents.java:7)
at androidx.test.espresso.action.MotionEvents.sendUp(MotionEvents.java:1)
at androidx.test.espresso.action.Tap.sendSingleTap(Tap.java:5)
at androidx.test.espresso.action.Tap.access$100(Tap.java:1)
at androidx.test.espresso.action.Tap$1.sendTap(Tap.java:3)
at androidx.test.espresso.action.GeneralClickAction.perform(GeneralClickAction.java:6)
at androidx.test.espresso.ViewInteraction$SingleExecutionViewAction.perform(ViewInteraction.java:2)
at androidx.test.espresso.ViewInteraction.doPerform(ViewInteraction.java:22)
at androidx.test.espresso.ViewInteraction.access$100(ViewInteraction.java:1)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:2)
at androidx.test.espresso.ViewInteraction$1.call(ViewInteraction.java:1)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7870)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

当你这样做的时候:

HomeFragment().also { fragment ->

你正在创建一个全新的片段,然后立即扔掉它-它永远不会添加到FragmentManager。

相反,您需要使用launchFragmentInHiltContainer已经为您创建的片段。假设您使用的launchFragmentInHiltContainer与文档中所说的相同,那么在lambda中已经可以使用被测试的片段,因此您的代码应该如下:

val scenario = launchFragmentInHiltContainer<HomeFragment>() {
// Your HomeFragment under test is already the 'this' in this lambda
viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
navController.setGraph(R.navigation.nav_graph)
Navigation.setViewNavController(fragment.requireView(), navController)
}
}

ianhanniballake的回复非常完美。今天早上我还找到了另一个解决办法。如果出于任何原因,有人想要不同的方法,请遵循下面的提交。

它是通过测试navHostController到HiltExt类,并将其添加到那里的片段。在调用setViewNavController

之前,我还必须设置nav_graph使其工作。https://github.com/android/architecture-samples/pull/752/files

相关内容

  • 没有找到相关文章

最新更新