streetsofboston
12/29/2017, 10:36 PMdelay
calls in the code under test necessitate the need for our tests to call runBlocking
to get the proper test-results/assertions. This can cause the running of unit test-suites to take a long time.
I thought I would write my own CoroutineContext
implementation to be able to write non-blocking unit test, much like the TestScheduler
does for testing Rx Java.
I managed to write a simple CoroutineContext
called TestCoroutineContext
which I based upon the already available HandlerContext
. But instead of an android Handler
, I wrote my own proprietary ‘handler’ (one that takes `Runnable`s to be executed asap, later or to be canceled). In addition, I added methods called advanceTimeBy
, advanceTimeTo
and triggerActions
to this TestCoroutineContext
to simulate the passing of time.
E.g. now I can do this kind of unit-test (use launch
instead of runBlocking
)
Before
@ Test
fun configureMeshNetwork() {
// This test will take about 3 seconds
val delay = 3000L
runBlocking {
// launchWithDelay runs a coroutine with a `delay`.
presenter.launchSignInWithDelay(delay)
}
verify(mockView).launchSignInActivity()
}
After, using a `TestCoroutineContext`:
@ Test
fun configureMeshNetwork() {
// This test will take a few milliseconds
val delay = 3000L
launch(testCoroutineContext) {
// launchWithDelay runs a coroutine with a `delay`.
presenter.launchSignInWithDelay(delay)
}
testCoroutineContext.advanceTimeBy(delay)
verify(mockView).launchSignInActivity()
}
My questions are:
- Is using the kotlinx.coroutines.experimental.android.HandlerContext
class as a template for my TestCoroutineContext
good enough or would my subclass need to implement more of its superclasses’ methods?
- Currently, the functions such as launch
or async
take a CoroutineContext as an input parameter which is defaulted to a fixed value. Would it be possible to have these functions use a provider/hook so that unit-tests can provide their own contexts to these functions if needed?