https://kotlinlang.org logo
#coroutines
Title
# coroutines
g

gumil

01/22/2019, 9:01 PM
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

Allan Wang

01/22/2019, 9:01 PM
wrap it with
runBlocking
then use
.join()
g

gumil

01/22/2019, 9:05 PM
What if the call to
launch
is abstracted? I don't have access to the
job
g

ghedeon

01/22/2019, 9:05 PM
is join required? iiric,
runBlocking
is enough. Plus, you need to override Main dispatcher on Android
a

Allan Wang

01/22/2019, 9:08 PM
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

gumil

01/22/2019, 9:13 PM
hmm so does
runBlocking { joinAll() }
work too?
a

Allan Wang

01/22/2019, 9:15 PM
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

Dico

01/23/2019, 3:03 AM
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

gumil

01/23/2019, 9:25 AM
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

Dico

01/23/2019, 9:32 AM
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

gumil

01/23/2019, 9:45 AM
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

Dico

01/23/2019, 9:48 AM
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

ghedeon

01/23/2019, 10:06 AM
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

gumil

01/23/2019, 10:30 AM
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

ghedeon

01/23/2019, 10:44 AM
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

Dico

01/23/2019, 11:25 AM
Or
coroutineScope { foo.bar() }
2 Views