kotlinx.coroutines 1.6 introduces a set of recent testing APIs, and the earlier testing APIs are actually deprecated. Utilizing the previous APIs will produce deprecation errors quickly, they usually’re scheduled to be eliminated fully across the finish of 2022.
We have now lately printed a information on easy methods to use the brand new testing APIs, which explains how they work intimately. On this publish, we’ll deal with the migration from the previous APIs by taking a look at how we’ve migrated a few of our personal samples. Yow will discover hyperlinks to view the complete diffs on the finish of this publish.
The migration steps we took ought to cowl numerous the required work for many Android initiatives. If you happen to discover that these are usually not sufficient to your venture, you may check out the detailed migration information by JetBrains which covers superior usages of the testing APIs as nicely.
Begin with runTest
Let’s begin on the entry level of the brand new testing APIs, the
runTest coroutine builder. This replaces
runBlockingTest from the previous APIs, which could possibly be known as as a top-level operate, but it surely was additionally usually invoked on a take a look at scope, take a look at dispatcher, or take a look at rule.
We’ve changed all of those with calls to the top-level
If you happen to weren’t utilizing an expression physique (instantly returning
runTest’s outcome from the operate) but, it’s a good time to undertake that conference, too! It’s good for consistency, and it’s required if you happen to’ll ever use the coroutine testing APIs in a multiplatform venture with a KotlinJS goal.
Deal with the Important thread
Because the Android UI thread shouldn’t be obtainable in unit checks, any checks counting on the
Important dispatcher want to switch it with a
TestDispatcher implementation at some point of the take a look at. You’ll be able to both inject it like different dispatchers, or exchange it utilizing
setMain replaces the dispatcher in a static means, which signifies that you need to use constructs that depend on a hardcoded
Important dispatcher in your checks, resembling
A continuously used methodology for that is to place the code changing
Important right into a reusable JUnit take a look at rule (or for JUnit 5, a take a look at extension). You’ll be able to see an instance of such a rule within the iosched venture. If in case you have a rule like this utilizing the previous APIs, replace it like this:
The rule is then used like this, as a property of the take a look at class (unchanged from earlier than):
Be extra keen: amassing Flows
Checks usually begin new coroutines to gather values from Flows. These checks are likely to depend on these new coroutines being began eagerly, in order that every time the Circulate emits a worth the collector will already be able to course of it.
runBlockingTest begins new coroutines created inside the take a look at eagerly,
runTest begins them lazily as an alternative, because it makes use of a
StandardTestDispatcher for the take a look at coroutine by default.
To make Circulate-collecting coroutines in checks begin eagerly once more, create a brand new
UnconfinedTestDispatcher, and go it to the builder that creates the amassing coroutine:
Notice that on this code snippet, a brand new
TestDispatcher is created with out passing in a scheduler explicitly. That is secure to do provided that the
Important dispatcher has been changed by a
TestDispatcher, which makes scheduler sharing automated. In any other case, it’s a must to go within the present scheduler to any
TestDispatchers you create:
It’s additionally value remembering that calling acquire explicitly shouldn’t be the one technique to acquire a Circulate, different strategies like
Circulate.toList() additionally acquire the Circulate internally. If you happen to’re utilizing such strategies, you may additionally wish to name them in new coroutines which can be began with an
Be much less keen: Important dispatcher execution
As you’ve seen above within the implementation of
MainDispatcherRule, we default to utilizing
UnconfinedTestDispatcher for the
Important dispatcher to eagerly launch coroutines. That is helpful when testing ViewModels, the place utilizing
Dispatchers.Important.speedywould have related keen conduct in manufacturing code when known as from the primary thread.
Nevertheless, some checks in our samples wanted lazy scheduling for
Important dispatcher coroutines. Sometimes, this could be for checks that want to say an intermediate loading state of a ViewModel, the place eagerly beginning the data-loading coroutine would imply that the take a look at can solely observe the ultimate loaded state. With the previous APIs, these checks used
pauseDispatcher to stop new coroutines from executing too early, like this:
To carry out the identical take a look at with the brand new APIs, the
Important dispatcher must be set to a
StandardTestDispatcher, so we’d like a unique
TestDispatcher kind than what our rule makes use of by default. As the kind of
TestDispatcher used for
MainDispatcherRule impacts all checks inside the take a look at class, we had two decisions:
- cut up checks into two take a look at lessons based mostly on the kind of
Importantdispatcher wanted for every take a look at, utilizing a rule with a unique kind of dispatcher within the two take a look at lessons, or
- hold utilizing a single class the place the rule all the time units an
Important, after which override the
Importantdispatcher’s kind in only a few of the checks that require a unique kind.
We opted for the latter answer, beginning these checks by changing the already-replaced
Important with a brand new
StandardTestDispatcher to lazily begin new coroutines on
Important. Then, later within the take a look at code after we’d name
resumeDispatcher with the previous APIs, we are able to advance these coroutines through the use of
This strategy retains checks that belong collectively in the identical take a look at class, making the codebase simpler to navigate, with the tradeoff that some checks have to incorporate further code for changing
Important with the specified kind of
Clear up that cleanup code
Lastly, some fast tidying-up to do. The iosched pattern had some take a look at code that explicitly waited for coroutines to finish on the
TestCoroutineDispatcher earlier than the take a look at would finish:
runTest mechanically waits for all identified coroutines, which embrace youngsters of the take a look at coroutine and any coroutines operating on
TestDispatchers. This implies that you may simply take away any cleanup code that waits for some unfastened coroutines to finish!
These migration steps ought to get you a lot of the means towards utilizing the brand new coroutine testing APIs. For extra, you may try all of the modifications we made in our samples:
And naturally, the brand new Now in Android pattern app already makes use of the brand new testing APIs for its checks!
Lastly, if you happen to want extra assist with the migration, try the official migration information by JetBrains, which covers the intricacies of the coroutine testing API.