使用下面的代码来测试异常Flow
和MockK
@Test 乐趣given network error returned from repos, should throw exception
() = testCoroutineScope.runBlockingTest {
// GIVEN
every { postRemoteRepository.getPostFlow() } returns flow<List<PostDTO>> {
emit(throw Exception("Network Exception"))
}
// WHEN
var expected: Exception? = null
useCase.getPostFlow()
.catch { throwable: Throwable ->
expected = throwable as Exception
println("⏰ Expected: $expected")
}
.launchIn(testCoroutineScope)
// THEN
println("⏰ TEST THEN")
Truth.assertThat(expected).isNotNull()
Truth.assertThat(expected).isInstanceOf(Exception::class.java)
Truth.assertThat(expected?.message).isEqualTo("Network Exception")
}
和版画
⏰ TEST THEN
⏰ Expected: java.lang.Exception: Network Exception
并且测试失败了
expected not to be: null
我测试的方法是
fun getPostFlow(): Flow<List<Post>> {
return postRemoteRepository.getPostFlow()
// This method is just to show flowOn below changes current thread
.map {
// Runs in IO Thread DefaultDispatcher-worker-2
println("⏰ PostsUseCase map() FIRST thread: ${Thread.currentThread().name}")
it
}
.flowOn(Dispatchers.IO)
.map {
// Runs in Default Thread DefaultDispatcher-worker-1
println("⏰ PostsUseCase map() thread: ${Thread.currentThread().name}")
mapper.map(it)
}
// This is a upstream operator, does not leak downstream
.flowOn(Dispatchers.Default)
}
这不是一个完全实用的功能,只是为了检查 Dispatchers 如何使用 Flow 和测试。
在撰写我评论的问题时.flowOn(Dispatchers.IO)
,测试通过的最重要的问题。还将 Dispatchers.IO 更改为 Dispatchers.Default 并导致测试通过。我认为这是由于使用了不同的线程。
1-是否有一种功能或方法可以在不修改代码的情况下将所有 flowOn 方法设置为同一个线程?
这次我尝试测试成功场景
@Test
fun `given data returned from api, should have data`() = testCoroutineScope.runBlockingTest {
// GIVEN
coEvery { postRemoteRepository.getPostFlow() } returns flow { emit(postDTOs) }
every { dtoToPostMapper.map(postDTOs) } returns postList
val actual = postList
// WHEN
val expected = mutableListOf<Post>()
// useCase.getPostFlow().collect {postList->
// println("⏰ Collect: ${postList.size}")
//
// expected.addAll(postList)
// }
val job = useCase.getPostFlow()
.onEach { postList ->
println("⏰ Collect: ${postList.size}")
expected.addAll(postList)
}
.launchIn(testCoroutineScope)
job.cancel()
// THEN
println("⏰ TEST THEN")
Truth.assertThat(expected).containsExactlyElementsIn(actual)
}
当我尝试截取被注释掉的片段时,测试失败
java.lang.IllegalStateException: This job has not completed yet
job
如果已取消,似乎测试可以通过launchIn
,返回的测试job
通过。
2- 为什么收集作业没有被取消,它只在第一次flowOn
使用时发生Dispatchers.IO
?