Please find below a function using a coroutine to replace callback :
override suspend fun signUp(authentication: Authentication): AuthenticationError { return suspendCancellableCoroutine { auth.createUserWithEmailAndPassword(authentication.email, authentication.password) .addOnCompleteListener(activityLifeCycleService.getActivity()) { task -> if (task.isSuccessful) { it.resume(AuthenticationError.SignUpSuccess) } else { Log.w(this.javaClass.name, "createUserWithEmail:failure", task.exception) it.resume(AuthenticationError.SignUpFail) } } } }
Now I would like to unit testing this function. I am using Mockk :
@Test fun `signup() must be delegated to createUserWithEmailAndPassword()`() = runBlockingTest { val listener = slot<OnCompleteListener<AuthResult>>() val authentication = mockk<Authentication> { every { email } returns "email" every { password } returns "pswd" } val task = mockk<Task<AuthResult>> { every { isSuccessful } returns true } every { auth.createUserWithEmailAndPassword("email", "pswd") } returns mockk { every { addOnCompleteListener(activity, capture(listener)) } returns mockk() } service.signUp(authentication) listener.captured.onComplete(task) }
Unfortunately this test failed due to the following exception : java.lang.IllegalStateException: This job has not completed yet
I tried to replace runBlockingTest
with runBlocking
but the test seems to wait in an infinite loop.
Can someone help me with this UT please?
Thanks in advance
As can be seen in this post:
This exception usually means that some coroutines from your tests were scheduled outside the test scope (more specifically the test dispatcher).
Instead of performing this:
private val networkContext: CoroutineContext = TestCoroutineDispatcher() private val sut = Foo( networkContext, someInteractor ) fun `some test`() = runBlockingTest() { // given ... // when sut.foo() // then ... }
Create a test scope passing test dispatcher:
private val testDispatcher = TestCoroutineDispatcher() private val testScope = TestCoroutineScope(testDispatcher) private val networkContext: CoroutineContext = testDispatcher private val sut = Foo( networkContext, someInteractor )
Then in test perform testScope.runBlockingTest
fun `some test`() = testScope.runBlockingTest { ... }
See also Craig Russell's "Unit Testing Coroutine Suspend Functions using TestCoroutineDispatcher"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With