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

MockK单元测试对比LiveData模拟对象时assertEquals失败如何解决

问题原因

报错是对象初始化顺序和MockK打桩时机不匹配导致的:

  1. Repository的response是类初始化阶段就直接赋值的属性,实例化Repository时就会立刻调用dao.getAllObjects()获取值
  2. 你的测试用了@InjectMockKs注解,MockKAnnotations.init(this)执行时就会直接实例化Repository并注入依赖,这时候你还没有执行every { dao.getAllObjects() } returns mockLiveData打桩逻辑
  3. 因为你开了relaxed = true,MockK会为未打桩的dao.getAllObjects()自动生成一个默认的临时LiveData对象赋值给repository.response,后续你在测试方法里的打桩已经不会影响已经完成初始化的response属性了,所以两个对象不一致。

小提示:如果没有特殊需求,单元测试尽量不要开relaxed = true,未打桩的方法调用直接抛出异常能更快帮你定位初始化顺序、漏打桩这类问题。

修复方案

方案1:不修改生产代码,调整测试逻辑

放弃@InjectMockKs自动注入,在打桩完成后手动创建Repository实例即可,修改后的测试代码如下:

class RepositoryTest {

    @MockK
    private lateinit var mockLiveData: LiveData<List<MyObject>>

    @MockK
    private lateinit var mockDao: Dao

    // 移除@InjectMockKs注解,手动控制实例化时机
    private lateinit var repository: Repository

    init {
        MockKAnnotations.init(this, relaxed = true)
    }

    @Test
    fun `Verify my objects are loaded from the database`() {
        // 先完成打桩
        every { dao.getAllObjects() } returns mockLiveData
        // 打桩完成后再手动实例化Repository
        repository = Repository(mockDao)
        // 执行断言
        verify { dao.getAllObjects() }
        assertEquals(mockLiveData, repository.response)
    }
}

方案2:修改生产代码属性为懒加载,无需调整现有测试逻辑

把Repository的response改为懒加载属性,只有第一次访问该属性时才会执行dao.getAllObjects(),这样打桩时机就早于属性赋值时机:

class Repository @Inject constructor(private val dao: Dao) {
    // 增加by lazy关键字改为懒加载
    val response: LiveData<List<MyObject>> by lazy { dao.getAllObjects() }
    ...
}

该方案下你原有测试代码不需要任何修改,直接运行即可通过。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 07:30:05