我有以下代码:
class Feature(scope:CoroutineScope = CoroutineScope(Dispatchers.IO)){
val dataStore: DataStore<MetaDataStore> = context.createDataStore(
fileName = PREFERENCES,
serializer = MetadataSerializer,
scope = scope
)
fun foo() {
}
}
测试类时我想检查函数 foo
runBlockingTest {
val feature = Feature(this)
feature.foo()
verifyStuff...
}
使用 TestCoroutineScope 非常重要,因为它可以确保所有异步内容都已完成 不幸的是我收到一条错误消息:
kotlinx.coroutines.test.UncompletedCoroutinesError:测试已完成活动作业:[“coroutine#2”:ActorCoroutine {Active}@31b46ea7]
这是有道理的,因为数据存储可能使用后台任务,但是我如何使用 android 数据存储测试类?
我还在谷歌问题跟踪器中问了这个问题: https://issuetracker.google.com/issues/177856517
与此同时,我支持一些模拟实现并将其注入到构造函数中。
import androidx.datastore.core.DataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
class DatastoreInmemoryImpl<T>(defaultValue:T) : DataStore<T> {
val sharedFlow = MutableStateFlow(defaultValue)
val mutex = Mutex()
override val data: Flow<T> = sharedFlow.asStateFlow()
override suspend fun updateData(transform: suspend (t: T) -> T): T = mutex.withLock {
sharedFlow.value = transform.invoke(sharedFlow.value)
sharedFlow.value
}
}
但是我应该能够使用数据存储来使用类,而不需要将其作为构造函数参数注入
谷歌的人回答了我。
有一个测试示例这里
主要思想是创建一个与封闭测试范围不同的范围,然后取消它
所以
runBlockingTest {
val dataStoreScope = TestCoroutineScope(TestCoroutineDispatcher() + Job())
val feature = Feature(dataStoreScope)
<put your test code here>
dataStoreScope.cancel()
dataStoreScope.cleanupTestCoroutines()
}
datastoreScope 创建和 datastoreScope.cleanupTestCoroutines 可以放在 @Before 和 @After 函数中。
他们告诉我他们正在为以后的版本开发更好的解决方案
根据 Version 1.1.0-rc01 的发行说明,建议似乎是使用 TestScope.backgroundScope 传递到
PreferenceDataStoreFactory.create([here]...
以便在 runTest
上运行测试