You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

低SDK版本下如何Mock注入ViewModel中的userObserver(LiveData<UserResponse>)

问题描述
class CustomActivity : BaseActivity() {

@Inject
lateinit var viewModelFactory: ViewModelProviderFactory

private val mViewModel: SplashViewModel by viewModels {
    viewModelFactory
}

override fun onResume() {
    super.onResume()
    observeOrderResponse()
}

private fun observeOrderResponse() {
    mViewModel.userObserver.observe(this) { userResponse ->
        updateUIBasedOnUserResponse(userResponse)
    }
}

在上述代码中,需要使用指定的UserResponse来Mock userObserver(LiveData<UserResponse>),但应用最低SDK版本为26,无法使用AppComponentFactory,该如何Mock这个依赖注入的ViewModel中的观察者?


解决方案

方法一:直接Mock ViewModel并替换实例

借助MockK或Mockito这类Mock框架,创建预设了userObserver的ViewModel实例,再通过反射替换Activity中的mViewModel:

// 测试示例(使用MockK)
@Test
fun testUserResponseHandling() {
    // 1. 构造测试用的UserResponse
    val testUserResponse = UserResponse(/* 填充测试所需字段 */)
    // 2. 创建包含测试数据的LiveData
    val testLiveData = MutableLiveData<UserResponse>().apply { value = testUserResponse }
    // 3. Mock SplashViewModel,指定userObserver返回测试LiveData
    val mockViewModel = mockk<SplashViewModel>()
    every { mockViewModel.userObserver } returns testLiveData

    // 4. 启动Activity并替换ViewModel实例
    val activity = launchActivity<CustomActivity>().get()
    val viewModelField = CustomActivity::class.java.getDeclaredField("mViewModel")
    viewModelField.isAccessible = true
    viewModelField.set(activity, mockViewModel)

    // 5. 触发观察逻辑,验证UI更新
    activity.onResume()
    // 此处添加验证updateUIBasedOnUserResponse执行结果的逻辑,比如检查UI控件状态
}

方法二:使用测试专用的ViewModelFactory

为测试场景实现自定义的ViewModelProviderFactory,直接返回预设好userObserver的ViewModel,再替换Activity中的工厂实例:

// 测试用Factory实现
class TestSplashViewModelFactory(private val targetViewModel: SplashViewModel) : ViewModelProviderFactory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return targetViewModel as T
    }
}

// 测试方法
@Test
fun testWithCustomFactory() {
    val testUserResponse = UserResponse(/* 测试数据 */)
    val testLiveData = MutableLiveData<UserResponse>().apply { value = testUserResponse }

    // 创建ViewModel实例并修改其userObserver
    val testViewModel = SplashViewModel()
    val observerField = SplashViewModel::class.java.getDeclaredField("userObserver")
    observerField.isAccessible = true
    observerField.set(testViewModel, testLiveData)

    // 初始化测试用Factory并注入Activity
    val testFactory = TestSplashViewModelFactory(testViewModel)
    val activity = launchActivity<CustomActivity> {
        val factoryField = CustomActivity::class.java.getDeclaredField("viewModelFactory")
        factoryField.isAccessible = true
        factoryField.set(this, testFactory)
    }.get()

    activity.onResume()
    // 验证UI更新逻辑
}

方法三:结合LiveData测试工具同步执行

使用InstantTaskExecutorRule让LiveData在测试中同步执行,避免异步回调的时序问题,搭配Mock框架控制数据输出:

// 添加测试规则,确保LiveData同步执行
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()

@Test
fun testLiveDataObserverSync() {
    val testUserResponse = UserResponse(/* 测试数据 */)
    val testLiveData = MutableLiveData<UserResponse>()
    val mockViewModel = mockk<SplashViewModel>()
    every { mockViewModel.userObserver } returns testLiveData

    val activity = launchActivity<CustomActivity>().get()
    // 替换ViewModel实例
    val viewModelField = CustomActivity::class.java.getDeclaredField("mViewModel")
    viewModelField.isAccessible = true
    viewModelField.set(activity, mockViewModel)

    // 触发观察后发送测试数据
    activity.observeOrderResponse()
    testLiveData.postValue(testUserResponse)

    // 验证UI是否正确响应数据
}

注意事项

  • 反射操作需要确保目标字段(mViewModel、viewModelFactory或ViewModel中的userObserver)的可见性,通过setAccessible(true)开启访问权限
  • 若userObserver是private修饰的可变LiveData,需通过反射修改其值;如果是只读的,直接Mock返回预设LiveData即可
  • InstantTaskExecutorRule属于androidx.arch.core:core-testing库,需确保测试依赖中已引入

内容的提问来源于stack exchange,提问作者Maradiya Krupa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 07:28:14