Android 测试无法使用 Dagger 提供的 ViewModel 执行 Fragment 检测测试,在 ViewModelProvider 参数所有者上遇到 NullPointerException

问题描述 投票:0回答:1

我有一个片段,其 ViewModel 实例由组件提供,范围仅限于主活动的导航图。 Dagger 应用程序组件被注入到单个主活动中,并作为惰性委托变量抓取到片段内。

private val myViewModel: MyViewModel by lazy {
        ViewModelProvider(findNavController().getBackStackEntry(R.id.nav_graph), Factory(this) { stateHandle ->
            (activity as MainActivity).myComponent.myViewModel()
                .create(stateHandle)}).get(MyViewModel::class.java)
    }

ViewModelProvider 的 ViewModelProvider.Factory 参数使用 MyViewModel 类中定义的 Factory 接口的 create 方法;该接口使用@AssistedFactory进行注释,而savedStateHandle是在MyViewModel构造函数中使用@AssistInject进行注释。

class MyViewModel @AssistedInject constructor(
    private val myRepository: MyRepository,
    @Assisted val savedStateHandle: SavedStateHandle
    ) : ViewModel() {

    @AssistedFactory
    interface MyViewModelFactory : ViewModelProvider.Factory {
        fun create(savedStateHandle: SavedStateHandle) : MyViewModel
    }

    //Other ViewModel code 
}

应用程序运行良好,Dagger 应用程序组件通过其惰性委托获取我提供的 MyViewModel 实例,但现在当我尝试编写一个仪器测试来测试 Fragment 本身的一些 ui 字段时,我遇到了空点异常。具体来说:

java.lang.NullPointerException: Parameter specified as non-null is null: method androidx.lifecycle.ViewModelProvider.<init>, parameter owner
at androidx.lifecycle.ViewModelProvider.<init>(Unknown Source:2)

这告诉我所有者参数,

findNavController().getBackStackEntry(R.id.nav_graph)
NPE 失败,但我不知道如何解决它,以便我的测试可以编译和执行。

这是到目前为止我的测试代码,请帮助我在这里缺少的地方,否则我可能会尝试删除 Dagger 并实例化所有内容以开始测试,回想起来这听起来像是倒退。我什至不确定我是否正确编写了这个测试场景,因为我正在尝试通过各种帮助论坛和此网站传播的解决方案大杂烩,以解决我的编译时问题和构建失败的问题。

@RunWith(AndroidJUnit4::class)
class MyFragmentTest {

    @get:Rule
    var activityRule = ActivityScenarioRule(MainActivity::class.java)

    private lateinit var scenario: FragmentScenario<MyFragment>
    private lateinit var binding: FragmentMyBinding
    private lateinit var mockNavController : NavController
    
    @Test
    fun setUp() {
        mockNavController = mock(NavController::class.java)
        scenario = launchFragmentInContainer<MyFragment> {
            MyFragment().also { fragment ->
                fragment.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
                    if (viewLifecycleOwner != null) {
                        // The fragment’s view has just been created
                        mockNavController.setGraph(R.navigation.nav_graph)
                        Navigation.setViewNavController(fragment.requireView(), mockNavController)
                    }
                }
            }
        }
    }

任何正确方向的帮助或指导将不胜感激,因为我已经被困在这里一段时间了。

kotlin android-fragments dagger-2 android-testing viewmodelproviders
1个回答
0
投票

用我如何让它工作来回答我自己的问题:使用 TestNavHostController。

@Test
fun setUp() {
        mockNavController = TestNavHostController(ApplicationProvider.getApplicationContext())
        scenario = launchFragmentInContainer<MyFragment> {
            MyFragment().also { fragment ->
                fragment.viewLifecycleOwnerLiveData.observeForever { viewLifecycleOwner ->
                    if (viewLifecycleOwner != null) {
                        // The fragment’s view has just been created

                        fragment.requireActivity().runOnUiThread {
                            mockNavController.setViewModelStore(ViewModelStore())
                            mockNavController.setGraph(R.navigation.base_nav_graph)
                            Navigation.setViewNavController(fragment.requireView(), mockNavController)
                        }
                    }
                }
            }
        }

这样我就解决了实例化视图模型的问题。

© www.soinside.com 2019 - 2024. All rights reserved.