Migrating to the brand new coroutines 1.6 take a look at APIs | by Marton Braun | Android Builders | Jun, 2022


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 runTest operate:

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.

In some superior circumstances, you may nonetheless wish to create your individual TestScope, however most checks will want solely to name runTest by itself.

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 Dispatchers.setMain. 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 viewModelScope.

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.

Whereas 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 UnconfinedTestDispatcher.

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 Important dispatcher 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 UnconfinedTestDispatcher for Important, after which override the Important dispatcher’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 TestDispatcher in 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 advanceUntilIdle.

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 TestDispatcher.

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:

Nevertheless, 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.



Leave a Comment