Testing Coroutines — Remainder

Photo by Kotagauni Srinivas on Unsplash

In the last part of the series on the testing coroutines with the kotlinx-coroutines-test module, we will have a look at remaining topics like exception handling, pausing the dispatcher and some more stuff.

Exception Handling

If we want to test for exceptions in coroutines we could do so using the good old :

This works since rethrows the first occurring exception if no one cares for it. An alternative is to provide a dedicated in the context, which will be called on every rising exception. The function adds a to the context to do so. This handler also throws the first occurring exception on cleanup, but also allows to inspect all exceptions during the test:

So this might be quite helpful in some cases. But it also may have some unexpected effects you should be aware of. A is usually used if you do NOT want the supervising scope to fail, if one of the children fails. So let's see the following example, would you expect it to succeed?

Nope, it fails. This is due the exception handler provided by which is passed to the supervisor scope. It handles all exceptions and rethrows it. If you use it would run right through.

So what if I do want to make use of all those goodies of without having a handler throwing exceptions? You could provide a custom handler that either does nothing at all, or one that just collects all exceptions but does not rethrow. This has the benefit that you can still analyze exceptions in your test:

Pausing the Dispatcher

As explained in the first part, the executes new coroutines immediately like they where started in mode . This behaviour can be changed by pausing the dispatcher, see the following example. Be aware that these example do not make any sense and are solely intended to demonstrate order of execution:

Due to the call to , the launched coroutine is NOT executed immediately, that's why state is still . Calling makes the dispatcher forward all coroutines up the current virtual time, so it proceeds up to the and therefore state == 2. To proceed we could either advance time (by 1000), or to run right through.

To complement there is also a . This switches execution back to immediate mode, but also advances all coroutines until idle. See the following example:

To complete this, there is also a variant that executes a given block of code. After the block is executed, it also resumes the dispatcher automatically:

Detecting Unrelated Jobs

The resp. is quite dependent on the to make time control work properly. But it has some built in feature in order to detect misusage. Let's recap our dispatcher provider example from part 3. We have a function that uses the dispatcher from the

… and the following test:

If you run this test, you will get:

java.lang.IllegalStateException: This job has not completed yet

Why is that? Ooops, we accidently used instead of. So the test dispatcher will not be passed through the provider, but the original is used. If we run the test, it will automatically advance until idle. But since we are not using the test dispatcher, it will not advance our coroutine :-(

Luckily has a safety belt: it counts all jobs before and after test execution. If there is a difference, it complains with the exception you saw above, and therefore gives you hint that something is wrong with your test :-)

That’s it, we’re done. There are quite a lot things you can do with the kotlinx-coroutines-test module, so give it a try. Be aware that the API is still experimental, so things are subject to change. You will find all examples and the utility functions in the accompanying git repository.

You’re damned if you do and
you’re damned if you don’t.
Bart Simpson

Developer @ https://www.compeople.de. Married, two children. Playing bass guitar.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store