Estoy trabajando con un proyecto de Android que necesita inicializar el token de Firebase. Principalmente trabajando con rutinas de Kotlin, me gustaría implementar el código línea por línea, pero dado que no hay forma de solicitar de forma sincrónica el token de Firebase, se me ocurrió la solución para envolver OnCompleteListener usando la siguiente función:
private suspend fun fcmCallbackSuspendWrapper(block: (OnCompleteListener<InstanceIdResult>) -> Unit) = suspendCancellableCoroutine<Task<InstanceIdResult>> { cont -> block(OnCompleteListener { response -> cont.resume(response) }) }Básicamente, bloquea el hilo actual hasta que Task llama a la devolución de llamada. Luego estoy aplicando dicha función en mi código de la siguiente manera:
val fcmInstance = fcmCallbackSuspendWrapper { listener -> fireBaseInstanceIdProvider .provide() // Returns Firebase instance .instanceId // Returns Task<InstanceIdResult> .addOnCompleteListener(listener) // Sets listener to block current thread until completed }Pero ahora necesito agregar una prueba unitaria al código anterior y aquí encuentro varios problemas:
@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) Pero dado que Task<InstanceIdResult> se burla, nunca se llama a OnCompleteListener<TResult> y el subproceso se bloquea para siempre, preservando la ejecución del código para continuar. ¿Qué se puede hacer en esta situación?
Lo he hecho usando Mockk.io , este es mi fragmento de código, con mockito creo que puedes hacer lo mismo
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 mockedInstanceIdGracias @mcatta tu fragmento me ayudó :)
Sin embargo, dado que FirebaseIntanceId está en desuso, esta es la nueva forma de hacerlo:
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