Ale*_*kov 4 android unit-testing kotlin
我正在处理需要初始化 Firebase 令牌的 Android 项目。主要使用 Kotlin 协程,我想逐行实现代码,但由于无法同步请求 Firebase 令牌,我想出了使用OnCompleteListener以下函数进行包装的解决方案:
private suspend fun fcmCallbackSuspendWrapper(block: (OnCompleteListener<InstanceIdResult>) -> Unit)
= suspendCancellableCoroutine<Task<InstanceIdResult>> { cont ->
block(OnCompleteListener { response ->
cont.resume(response)
})
}
Run Code Online (Sandbox Code Playgroud)
它基本上会阻塞当前线程,直到任务调用回调为止。然后我通过以下方式在我的代码中应用所述函数:
val fcmInstance = fcmCallbackSuspendWrapper { listener ->
fireBaseInstanceIdProvider
.provide() // Returns Firebase instance
.instanceId // Returns Task<InstanceIdResult>
.addOnCompleteListener(listener) // Sets listener to block current thread until completed
}
Run Code Online (Sandbox Code Playgroud)
但现在我需要在上面的代码中添加单元测试,这里我遇到了几个问题:
@Mock lateinit var instanceIdResultTaskMock: Task<InstanceIdResult>
@Mock lateinit var fireBaseInstanceIdProviderMock: Provider<FirebaseInstanceId>
@Mock lateinit var firebaseInstanceIdMock: FirebaseInstanceId
...
Mockito.`when`(fireBaseInstanceIdProviderMock.provide()).thenReturn(firebaseInstanceIdMock)
Mockito.`when`(firebaseInstanceIdMock.instanceId).thenReturn(instanceIdResultTaskMock)
Run Code Online (Sandbox Code Playgroud)
但由于Task<InstanceIdResult>被嘲笑 - 它OnCompleteListener<TResult>永远不会被调用并且线程被永远阻塞,保留代码执行继续。在这种情况下可以做什么?
小智 8
我已经使用Mockk.io完成了它,这是我的代码片段,使用mockito我认为你可能会做同样的事情
val mockedResult = mockk<InstanceIdResult>()
every { mockedResult.token } returns "token"
val mockedInstanceId = mockk<Task<InstanceIdResult>>()
every { mockedInstanceId.isSuccessful } returns true
every { mockedInstanceId.result } returns mockedResult
val slot = slot<OnCompleteListener<InstanceIdResult>>()
every { mockedInstanceId.addOnCompleteListener(capture(slot)) } answers {
slot.captured.onComplete(mockedInstanceId)
mockedInstanceId
}
every { firebaseInstanceId.instanceId } returns mockedInstanceId
Run Code Online (Sandbox Code Playgroud)
小智 6
谢谢@mcatta你的片段帮助了我:)
然而,由于 FirebaseIntanceId 已被弃用,这是执行此操作的新方法:
mockkStatic("com.google.firebase.messaging.FirebaseMessaging")
val firebaseMessagingMock = mockk<FirebaseMessaging>()
every { getInstance() } returns firebaseMessagingMock
val mockGetTokenTask = mockk<Task<String>>()
every { firebaseMessagingMock.token} returns mockGetTokenTask
val slot = slot<OnCompleteListener<String>>()
every { mockGetTokenTask.addOnCompleteListener(capture(slot)) } answers {
slot.captured.onComplete(mockGetTokenTask)
mockGetTokenTask
}
every {mockGetTokenTask.exception} returns null
every {mockGetTokenTask.result} returns currentToken
Run Code Online (Sandbox Code Playgroud)