How do you test coroutines started with `launch`? ...
# coroutines
g
How do you test coroutines started with
launch
? If I understand correctly
launch
always run asynchronously and in tests we would like to run it sequentially.
a
wrap it with
runBlocking
then use
.join()
g
What if the call to
launch
is abstracted? I don't have access to the
job
g
is join required? iiric,
runBlocking
is enough. Plus, you need to override Main dispatcher on Android
a
run blocking might be enough. It might wait for all child launches to run, so you have to ensure the scopes are used properly
g
hmm so does
runBlocking { joinAll() }
work too?
a
I think it’s provided that the scope has a job, and everything you are waiting on are children of that job. Easiest way may be to just try.
d
Yeah, parent job cannot complete until the children completed, so
parent.join()
should join all.
launch
is not always asynchronous, it depends on the coroutine context.
g
the problem I had was
launch
is abstracted so I am not able to get the
job
. I had to wrap it in an
async
block and
await()
until everything is finished. Do you guys know a cleaner way to do this?
d
coroutineContext[Job]
No I don't really get what you're talking about
It's confusing and ambiguous
But the above is available in any suspend function or lambda
g
Copy code
fun main(args: Array<String>) = runBlocking {
    abstractedCallToLaunch() // which I cannot get the job of the call to launch
    println("this should execute after call to launch")
}

fun CoroutineScope.abstractedCallToLaunch() {
    launch {
        delay(1000)
        println("do something")
    }
}
it’s something like this and it prints
Copy code
this should execute after call to launch
do something
but it should be the other way around
d
It's like that because of the dispatcher provided by
runBlocking
which is an event loop on the blocked thread.
You could try
coroutineContext[Job]!!.joinChildren()
I think that exists, after your 'abstracted' launch
Or just
yield()
should work too, but it might not wait for full completion
g
I feel like you expect something like
RxAndroidPlugins/InstantTaskExecutorRule
but it's not coming: https://github.com/Kotlin/kotlinx.coroutines/issues/102. Basically, your
launch
has a dispatcher attached, so it's considered your responsibility to inject the right dispatcher in your test, so the execution becomes synchronous.
g
Yep something like it. I’m passing a dispatcher but
launch
always run asynchronously. I’m not sure how to make it run synchronously
g
Hm.. what about as simple as: https://pl.kotl.in/r1F5BarQE
Basically:
Copy code
fun test(){
        blah blah
        runBlocking{
                 foo.bar() // <-- launch inside
         }
         assert(...)
}
d
Or
coroutineScope { foo.bar() }