使用Flow+Firestore的Android Repository层集成测试await超时问题
问题根因
Firebase Task 的完成回调默认会被调度到Android主线程执行,你的测试父类已将Dispatchers.Main替换为TestCoroutineDispatcher,而你在测试中使用普通runBlocking执行代码时,TestCoroutineDispatcher默认不会自动执行队列中的待处理任务,导致Task的完成回调永远不会被调用,kotlinx-coroutines-play-services提供的await()扩展会一直等待回调触发,因此出现永久阻塞。
解决方案
方案1:使用父类封装的runBlockingTest执行测试逻辑
替换测试方法中的runBlocking为父类已经封装好的runBlockingTest,它会自动调度TestCoroutineDispatcher队列中的任务,确保Task的回调可以正常执行:
@ExperimentalTime @Test fun `#getExercises returns a flow of exercises`() = runBlockingTest { val exercises = mutableListOf<Exercise>().apply { add(Exercise("a", "pushups")) add(Exercise("b", "pull-ups")) add(Exercise("c", "sit-ups")) } val task1 = firestoreInstance.collection(EXERCISES_REF).add(exercises.first()) val task2 = firestoreInstance.collection(EXERCISES_REF).add(exercises[1]) val task3 = firestoreInstance.collection(EXERCISES_REF).add(exercises.last()) Tasks.await(task1) Tasks.await(task2) Tasks.await(task3) println("Done with tasks: task1: ${task1.isComplete}. task2: ${task2.isComplete}. task3: ${task3.isComplete}.") println("About to get exercises") subject.getExercises().test(timeout = Duration.seconds(5)) { println("test body") assertThat(awaitItem().size, `is`(3)) } }
方案2:为Flow指定独立的IO调度器
在Repository的Flow构造时指定flowOn(Dispatchers.IO),让Task的回调执行在不受测试调度器控制的IO线程上,避开测试主线程调度器的限制:
fun getExercises() = flow<List<Exercise>> { println("beginning of searchForExercise") val exercises = exerciseCollRef.limit(5).get().await() println("Exercise count: ${exercises.documents}") emit(exercises.toObjects(Exercise::class.java)) }.flowOn(Dispatchers.IO) // 新增这行
方案3:替换为阻塞式Tasks.await
如果不想调整调度器配置,可以把kotlin扩展的await()替换为Google官方提供的阻塞式Tasks.await方法,它不依赖协程调度器的回调触发,直接阻塞当前线程等待Task完成:
fun getExercises() = flow<List<Exercise>> { println("beginning of searchForExercise") // 替换await()为Tasks.await,需要运行在IO调度器避免阻塞主线程 val exercises = Tasks.await(exerciseCollRef.limit(5).get()) println("Exercise count: ${exercises.documents}") emit(exercises.toObjects(Exercise::class.java)) }.flowOn(Dispatchers.IO)
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

