从测试中的挂起函数调用时,我的 MutableStateFlow 不发出
My MutableStateFlow doesnt emit when called from suspend function in test
我正在尝试为我的存储库编写测试,它提供对我的房间数据库的访问。
为此,我写了一个模拟数据库和一个模拟 DAO:
我的数据库:
abstract class JoozdlogDatabase protected constructor(): RoomDatabase() {
abstract fun aircraftTypeDao(): AircraftTypeDao
// (...)
}
class MockDatabase: JoozdlogDatabase() {
override fun aircraftTypeDao(): AircraftTypeDao = MockAircraftTypeDao()
}
我的 DAO:
interface AircraftTypeDao {
@Query("SELECT * FROM AircraftTypeData")
suspend fun requestAllAircraftTypes(): List<AircraftTypeData>
@Query("SELECT * FROM AircraftTypeData")
fun aircraftTypesFlow(): Flow<List<AircraftTypeData>>
// etc etc //
}
class MockAircraftTypeDao: AircraftTypeDao {
private val simulatedDatabase = ArrayList<AircraftTypeData>()
private val simulatedFlow = MutableStateFlow<List<AircraftTypeData>>(listOf(AircraftTypeData("aap", "noot", false, multiEngine = false)))
override suspend fun requestAllAircraftTypes(): List<AircraftTypeData> = simulatedDatabase
override fun aircraftTypesFlow(): Flow<List<AircraftTypeData>> = simulatedFlow
override suspend fun save(vararg aircraftTypeData: AircraftTypeData) {
//println("${this::class.simpleName} Saving ${aircraftTypeData.size} type data")
simulatedDatabase.addAll(aircraftTypeData)
emit()
}
override suspend fun clearDb() {
println("${this::class.simpleName} Clear DB")
simulatedDatabase.clear()
emit()
}
private fun emit(){
println("emit() should emit ${simulatedDatabase.size} items")
simulatedFlow.update { simulatedDatabase.toList() } // also tried: simulatedFlow.value = simulatedDatabase.toList()
println("simulatedFlow.value is now ${simulatedFlow.value.size}")
}
我的测试数据:
object TestData {
val aircraftTypes = listOf(
AircraftType("Test Aircraft 1 (MP/ME)", "TAC1", multiPilot = true, multiEngine = true),
AircraftType("Test Aircraft 2 (SP/SE)", "TAC2", multiPilot = false, multiEngine = false)
)
}
和我的测试:
@Test
fun test() {
runTest {
var currentTypesList: List<AircraftType> = emptyList()
val aircraftRepository = AircraftRepository.mock(MockDatabase())
// DispatcherProvider.default() provides UnconfinedTestDispatcher(TestCoroutineScheduler()) for my test.
launch(DispatcherProvider.default()) {
aircraftRepository.aircraftTypesFlow.collect {
println("emitted ${it.size} flights: $it")
currentTypesList = it
}
}
aircraftRepository.replaceAllTypesWith(TestData.aircraftTypes)
delay(500)
println("Done waiting")
assertEquals (2, currentTypesList.size)
}
}
预期结果:测试通过。
收到的结果:java.lang.AssertionError: expected:<2> but was:<1>
对于单个断言
收到输出:
emitted 1 flights: [AircraftType(name=aap, shortName=noot, multiPilot=false, multiEngine=false)]
MockAircraftTypeDao Clear DB
emit() should emit 0 items
simulatedFlow.value is now 0
emit() should emit 2 items
simulatedFlow.value is now 2
Done waiting
现在,我整个上午都在做这个,我只是不明白为什么它除了第一个值什么都不收集。
我尝试过的事情:
制作流对象来测试我的收集器 -> 收集器正常
直接访问 DAO 中的流项 -> 不起作用
用 update
和 value =
设置 MutableStateFlow 的值 -> 都不起作用。
创建一个完全相同但不是从挂起函数调用的不同流对象:有效。
所以,我猜想调用挂起函数有什么地方做错了,但是 Flow 对象在延迟结束之前正在更新,它就是不会收集。
如果有人比我聪明得多并且可以解释我做错了什么,我将不胜感激。
我正在尝试为我的存储库编写测试,它提供对我的房间数据库的访问。 为此,我写了一个模拟数据库和一个模拟 DAO:
我的数据库:
abstract class JoozdlogDatabase protected constructor(): RoomDatabase() {
abstract fun aircraftTypeDao(): AircraftTypeDao
// (...)
}
class MockDatabase: JoozdlogDatabase() {
override fun aircraftTypeDao(): AircraftTypeDao = MockAircraftTypeDao()
}
我的 DAO:
interface AircraftTypeDao {
@Query("SELECT * FROM AircraftTypeData")
suspend fun requestAllAircraftTypes(): List<AircraftTypeData>
@Query("SELECT * FROM AircraftTypeData")
fun aircraftTypesFlow(): Flow<List<AircraftTypeData>>
// etc etc //
}
class MockAircraftTypeDao: AircraftTypeDao {
private val simulatedDatabase = ArrayList<AircraftTypeData>()
private val simulatedFlow = MutableStateFlow<List<AircraftTypeData>>(listOf(AircraftTypeData("aap", "noot", false, multiEngine = false)))
override suspend fun requestAllAircraftTypes(): List<AircraftTypeData> = simulatedDatabase
override fun aircraftTypesFlow(): Flow<List<AircraftTypeData>> = simulatedFlow
override suspend fun save(vararg aircraftTypeData: AircraftTypeData) {
//println("${this::class.simpleName} Saving ${aircraftTypeData.size} type data")
simulatedDatabase.addAll(aircraftTypeData)
emit()
}
override suspend fun clearDb() {
println("${this::class.simpleName} Clear DB")
simulatedDatabase.clear()
emit()
}
private fun emit(){
println("emit() should emit ${simulatedDatabase.size} items")
simulatedFlow.update { simulatedDatabase.toList() } // also tried: simulatedFlow.value = simulatedDatabase.toList()
println("simulatedFlow.value is now ${simulatedFlow.value.size}")
}
我的测试数据:
object TestData {
val aircraftTypes = listOf(
AircraftType("Test Aircraft 1 (MP/ME)", "TAC1", multiPilot = true, multiEngine = true),
AircraftType("Test Aircraft 2 (SP/SE)", "TAC2", multiPilot = false, multiEngine = false)
)
}
和我的测试:
@Test
fun test() {
runTest {
var currentTypesList: List<AircraftType> = emptyList()
val aircraftRepository = AircraftRepository.mock(MockDatabase())
// DispatcherProvider.default() provides UnconfinedTestDispatcher(TestCoroutineScheduler()) for my test.
launch(DispatcherProvider.default()) {
aircraftRepository.aircraftTypesFlow.collect {
println("emitted ${it.size} flights: $it")
currentTypesList = it
}
}
aircraftRepository.replaceAllTypesWith(TestData.aircraftTypes)
delay(500)
println("Done waiting")
assertEquals (2, currentTypesList.size)
}
}
预期结果:测试通过。
收到的结果:java.lang.AssertionError: expected:<2> but was:<1>
对于单个断言
收到输出:
emitted 1 flights: [AircraftType(name=aap, shortName=noot, multiPilot=false, multiEngine=false)]
MockAircraftTypeDao Clear DB
emit() should emit 0 items
simulatedFlow.value is now 0
emit() should emit 2 items
simulatedFlow.value is now 2
Done waiting
现在,我整个上午都在做这个,我只是不明白为什么它除了第一个值什么都不收集。 我尝试过的事情:
制作流对象来测试我的收集器 -> 收集器正常
直接访问 DAO 中的流项 -> 不起作用
用 update
和 value =
设置 MutableStateFlow 的值 -> 都不起作用。
创建一个完全相同但不是从挂起函数调用的不同流对象:有效。
所以,我猜想调用挂起函数有什么地方做错了,但是 Flow 对象在延迟结束之前正在更新,它就是不会收集。 如果有人比我聪明得多并且可以解释我做错了什么,我将不胜感激。