Kotlin中含await()的协程如何测试?mockk测试无响应排查
问题:MockK测试含
await()的挂起函数时测试无法结束 我尝试用MockK为包含await()的挂起函数编写测试,但测试始终无法结束。请问当前测试方法是否正确?有没有遗漏步骤?
测试代码
private lateinit var repository: AuthRepository private lateinit var databaseReference: DatabaseReference private lateinit var auth: FirebaseAuth @Before fun setUp() { mockkStatic(FirebaseAuth::class) auth = mockk() databaseReference = mockk() every { FirebaseAuth.getInstance() } returns auth repository = AuthRepository(databaseReference) } @Test fun login_Successful() = runBlocking { val email = "test@example.com" val password = "password" val authResult: AuthResult = mockk() val expectedResult = Resource.Success(authResult) coEvery { auth.signInWithEmailAndPassword(email, password).await() } returns authResult val result = repository.login(email, password) Assert.assertEquals(expectedResult, result) }
待测试代码
private val auth = FirebaseAuth.getInstance() suspend fun login(email: String, password: String): Resource<AuthResult> = try { val authResult = auth.signInWithEmailAndPassword(email, password).await() Resource.Success(authResult) } catch(e: FirebaseAuthException) { Resource.Error(e.errorCode) }
问题原因
测试无法结束的核心问题是:你直接在coEvery中mock了await()调用,但signInWithEmailAndPassword返回的AuthResultTask是未被mock的真实对象,它的await()方法会阻塞当前协程——真实的Task没有实际执行环境,会一直处于pending状态,导致测试卡住。
修复方案
需要分两步mock:先让signInWithEmailAndPassword返回一个mock的Task对象,再对这个mock对象的await()方法指定返回值。
修改后的测试代码:
private lateinit var repository: AuthRepository private lateinit var databaseReference: DatabaseReference private lateinit var auth: FirebaseAuth @Before fun setUp() { mockkStatic(FirebaseAuth::class) auth = mockk() databaseReference = mockk() every { FirebaseAuth.getInstance() } returns auth repository = AuthRepository(databaseReference) } @Test fun login_Successful() = runBlocking { val email = "test@example.com" val password = "password" val authResult: AuthResult = mockk() // 新增:mock Task对象 val authTask: Task<AuthResult> = mockk() val expectedResult = Resource.Success(authResult) // 第一步:mock signInWithEmailAndPassword返回mock的Task every { auth.signInWithEmailAndPassword(email, password) } returns authTask // 第二步:mock Task的await()方法返回预期结果 coEvery { authTask.await() } returns authResult val result = repository.login(email, password) Assert.assertEquals(expectedResult, result) }
额外补充
- 测试Firebase的
Task.await()时,必须确保Task本身是mock对象,否则真实Task会因无执行环境一直阻塞协程 - 若要测试异常分支(比如
FirebaseAuthException),可在coEvery中指定抛出异常:
coEvery { authTask.await() } throws FirebaseAuthException("error_code", "error_message")
内容的提问来源于stack exchange,提问作者Kleini
相关产品推荐
相关产品推荐

