Android协程JUnit测试失败: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
相关产品推荐
相关产品推荐

