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

如何用Mockk测试Observable的订阅调用?ViewModel测试遇断言异常

问题分析与解决

核心问题

  1. RxJava线程异步执行:测试里Schedulers.io()和AndroidSchedulers.mainThread()是异步调度的,verify会在订阅回调触发前执行,导致断言失败。
  2. init块调用时机冲突:subscribeToTablesUpdates()在ViewModel的init块中执行,测试代码里的mock设置是在ViewModel实例化之后,此时函数已经调用过,mock完全没生效。

解决方案

1. 让RxJava在测试中同步执行

在测试类的前后置方法里替换RxJava的调度器,强制所有操作在当前线程同步完成:

@Before
fun setup() {
    RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
    RxAndroidPlugins.setMainThreadSchedulerHandler { Schedulers.trampoline() }
}

@After
fun teardown() {
    RxJavaPlugins.reset()
    RxAndroidPlugins.reset()
}

这样订阅回调会立刻执行,verify就能捕捉到updateTablesState的调用。

2. 调整mock与ViewModel初始化顺序

因为函数在init块里,必须先把mock配置好,再创建ViewModel实例:

private lateinit var viewModel: YourViewModel
private val mockDataManager = mockk<DataManager>()

@Before
fun setup() {
    // 先配置RxJava同步调度
    RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
    RxAndroidPlugins.setMainThreadSchedulerHandler { Schedulers.trampoline() }
    
    // 先mock dataManager的返回值
    val mockedTablesList = mockk<List<Table>>()
    every { mockDataManager.getTablesList() } returns Observable.just(mockedTablesList)
    
    // 最后初始化ViewModel
    viewModel = YourViewModel(mockDataManager)
}

@Test
fun subscribeToTablesListTest() {
    val mockedTablesList = mockk<List<Table>>()
    // 不用手动调用subscribeToTablesUpdates,init块已经执行过了
    verify { viewModel.updateTablesState(mockedTablesList) }
}

注意:ViewModel的构造函数要接收dataManager参数,方便测试时传入mock实例。

3. 修正测试代码语法错误

原测试里mockk<List<Table>>()少了闭合尖括号,正确写法是mockk<List<Table>>()。

完整测试示例

class YourViewModelTest {
    private lateinit var viewModel: YourViewModel
    private val mockDataManager = mockk<DataManager>()

    @Before
    fun setup() {
        // 配置RxJava同步调度
        RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
        RxAndroidPlugins.setMainThreadSchedulerHandler { Schedulers.trampoline() }

        // Mock数据返回
        val mockedTablesList = mockk<List<Table>>()
        every { mockDataManager.getTablesList() } returns Observable.just(mockedTablesList)

        // 初始化ViewModel
        viewModel = YourViewModel(mockDataManager)
    }

    @After
    fun teardown() {
        // 重置RxJava配置,避免影响其他测试
        RxJavaPlugins.reset()
        RxAndroidPlugins.reset()
    }

    @Test
    fun subscribeToTablesListTest() {
        val mockedTablesList = mockk<List<Table>>()
        verify { viewModel.updateTablesState(mockedTablesList) }
    }
}

内容的提问来源于stack exchange,提问作者Nikita Vasko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 13:35:22