【发布时间】:2021-10-28 03:41:52
【问题描述】:
我正在尝试为 networkBoundResource 的 kotlin 版本编写一个 UnitTest,可以在 serveral sources 和 several features 上找到它
这是我对以下问题的标记-cmets 版本。
inline fun <ResultType, RequestType> networkBoundResource(
...
coroutineDispatcher: CoroutineDispatcher
) = flow {
emit(Resource.loading(null)) // emit works!
val data = queryDatabase().firstOrNull()
val flow = if (shouldFetch(data)) {
emit(Resource.loading(data)) // emit works!
try {
saveFetchResult(fetch())
query().map { Resource.success(it) }
} catch (throwable: Throwable) {
onFetchFailed(throwable)
query().map { Resource.error(throwable.toString(), it) }
}
} else {
query().map { Resource.success(it) }
}
emitAll(flow) // emitAll does not work!
}.catch { exception ->
emit(Resource.error("An error occurred while fetching data! $exception", null))
}.flowOn(coroutineDispatcher)
这是我对此代码的单元测试之一。对代码进行了一些编辑以专注于我的问题:
@get:Rule
val testCoroutineRule = TestCoroutineRule()
private val coroutineDispatcher = TestCoroutineDispatcher()
@Test
fun networkBoundResource_noCachedData_shouldMakeNetworkCallAndStoreUserInDatabase() = testCoroutineRule.runBlockingTest {
...
// When getAuthToken is called
val result = networkBoundResource(..., coroutineDispatcher).toList()
result.forEach {
println(it)
}
}
问题是println(it) 只打印Resource.loading(null) 排放量。但是如果你看一下flow {} 块的最后一行,你会发现应该有另一个val flow 的发射。但是这种排放永远不会到达我的单元测试中。为什么?
【问题讨论】:
-
你确定是
emitAll的问题吗?代码是否达到了这一点?此外,这可能是您的query流在测试上下文中没有发出任何内容的问题。 -
是的,我确定。如果我在
emitAll前面放置一个println,它就会被打印出来。此外,查询只是 UnitTest 上下文中的测试虚拟对象。 -
它对
Flow<T>api 的使用相当杂乱-具有副作用(保存到数据库)和FlowCollector<T>.()范围内的嵌套流和回调onFetchFailed(throwable)(这有什么意义?)当Flow<T>api 包含所有内容时出现错误。在测试它会产生异常或意外的行为时,我并不感到惊讶。喜欢编写自己的代码,而不是复制/粘贴其他人。 -
@MarkKeen 我明白你的观点并在一定程度上同意。再说一遍,这或多或少只是 Google 推荐的
NetworkBoundResource的 official implementation 的一个 kotlin 端口。不过,我只是从 Flow 开始……你愿意写一个更好的实现的伪代码版本吗? -
@Akhha8 我认为您将
toList()误认为first()。两者都是终端操作员,但toList()不应该给出第一个发射的项目,而是所有发射项目的列表。因此也是Resource.success。但是,我也用collect { println(it) }尝试了你的方法,但得到了相同的结果:只收集了 2 个加载排放。没有收到成功或错误发射。
标签: android unit-testing kotlin kotlin-coroutines kotlin-flow