I have something like the following in Kotlin:
class A {
fun a(): Unit = TODO()
}
fun foo(a: A) {
// Do something
CoroutineScope(Dispatchers.IO).launch {
delay(1000)
a.a()
}
// Do something else
}
I want to write a test that verifies that the method A.a() was called by foo():
class MyTest {
@Test
fun `weird test`() {
val mockA: A = mockk(relaxed = true)
foo(mockA)
verify(exactly = 1) { mockA.a() }
}
}
Clearly, the test is failing because it is not synchronized with the coroutine. I tried to use runTest, but foo() is not a suspending function, and it is hiding the creation of the scope inside it.
What can I do?
Pass CoroutineDispatcher to the tested method instead of creating them inside the tested method.
You can create a controllable CoroutineDispatcher - StandardTestDispatcher(this.testScheduler) using coroutineScope provided by runTest.
And explicitly complete all coroutines on the test dispatcher - advanceUntilIdle() before running your verifications or assertions.
class MyTest {
@Test
fun `weird test`() = runTest {
val mockA: A = mockk(relaxed = true)
foo(mockA, StandardTestDispatcher(this.testScheduler))
advanceUntilIdle()
verify(exactly = 1) { mockA.a() }
}
}
class A {
fun a(): Unit = TODO()
}
fun foo(a: A, dispatcher: CoroutineDispatcher) {
// Do something
CoroutineScope(dispatcher).launch {
delay(1000)
a.a()
}
// Do something else
}
Also you can pass CoroutineScope instead of CoroutineDispatcher.
But note that CoroutineScope gives access to coroutines lifecycle (e.g. it could be used to cancel coroutines)
So:
CoroutineScope to the function.CoroutineDispatcher and create CoroutineScope inside the function.The issue usually addressed in Android development: