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

Android协程JUnit测试失败:MutableSharedFlow未触发更新求助

MutableSharedFlow单元测试断言失败:预期值未接收

我是Kotlin测试新手,首次编写单元测试时遇到问题:实现了基于MutableSharedFlow的ChangesNotifier类,JUnit4测试用例断言失败,预期值为100,实际值为0,看起来updates并未发射数据。

相关代码

ChangesNotifier类

import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow

open class ChangesNotifier<T> {

    private val triggerFlow = MutableSharedFlow<T>()

    var updates = triggerFlow.asSharedFlow()

    suspend fun notify(data: T) {
        triggerFlow.emit(data)
    }
}

JUnit4测试代码

import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test

class ChangesNotifierTest {

    private lateinit var notifier: ChangesNotifier<Int>
    private var result = 0

    @Before
    fun setUp(){
        notifier = ChangesNotifier()
    }

    @Test
    fun `Check what notifier receiving updates`() = runTest {
        launch {
            notifier.updates.collectLatest {
                result = it
            }
        }

        launch {
            notifier.notify(100)
        }

        advanceUntilIdle()
        assertEquals(100, result)
    }
}

报错信息

expected:<100> but was:<0>
Expected :100
Actual   :0
<Click to see difference>

java.lang.AssertionError: expected:<100> but was:<0>
    at org.junit.Assert.fail(Assert.java:89)

解决建议

核心原因

MutableSharedFlow默认参数为replay=0、extraBufferCapacity=0,意味着没有活跃订阅者时,emit的事件会直接被丢弃。测试中两个launch是并行调度的,notify(100)的发射操作可能在collectLatest订阅完成前执行,导致事件丢失,result始终为初始值0。

修复方案1:确保订阅先启动再发射

不需要修改ChangesNotifier类,调整测试代码的执行顺序,先启动订阅并确保订阅生效后再执行发射:

@Test
fun `Check what notifier receiving updates`() = runTest {
    // 启动订阅任务
    val collectJob = launch {
        notifier.updates.collectLatest {
            result = it
        }
    }
    // 挂起当前协程,确保订阅已注册完成
    yield()

    // 执行发射操作
    notifier.notify(100)

    advanceUntilIdle()
    assertEquals(100, result)
    // 取消订阅任务,避免资源泄漏
    collectJob.cancel()
}

修复方案2:修改SharedFlow参数缓存事件

如果业务场景需要支持订阅前的事件被新订阅者接收,可以修改ChangesNotifier中MutableSharedFlow的初始化参数,设置replay=1(保留最新1个事件给新订阅者):

open class ChangesNotifier<T> {
    // 设置replay=1,新订阅者会收到最新的1个事件
    private val triggerFlow = MutableSharedFlow<T>(replay = 1)

    var updates = triggerFlow.asSharedFlow()

    suspend fun notify(data: T) {
        triggerFlow.emit(data)
    }
}

这种修改后,原测试代码无需调整即可通过断言。


内容的提问来源于stack exchange,提问作者De-Bill

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 16:57:31