This article doesn’t cover basic of coroutines usage. If you’re not familiar with them I can advice to read intro at kotlinx git repo.
Post describes difficulties when writing unit tests for code that use coroutines. Also in the end we show the solution for this problem.
Typical Android Architecture
Imagine that we have simple MVP architecture in app. Activity looks like this:
In presenter we use coroutines for async operations. Repository just emulates long running operation.
All works well, but now we need to test this code. Although we inject all dependencies explicit using constructor it is not easy to test our code. We use mockito library for testing. Also we need to add
runBlocking function usage to have ability work with coroutines and
After running test we see that it fails because of:
Cannot mock/spy class sample.dev.coroutinesunittests.ContentRepository
Mockito cannot mock/spy because :
— final class
We need to add
open keyword to
ContentRepository class and to function
After running test we see that it fails once again. Now it happened because
UI coroutine context use looper under the hood:
Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked
I find post about similar problem. You can see it here.
Author solve this problem moving logic of running coroutines to
CoroutineContextProvider and explicit usage.
Here is another solution: pass Coroutines context explicit using Presenter constructor and then use this context for starting coroutines. We need to create class
It just has two fields that has reference to same context as we used in code earlier. It should be
open and fields must have
open modifier to have opportunity to inherit this class and override it’s fields values for testing purpose. Also we need to use initialization
by lazy to initialize value only when they used first time.
Now we should add usage of this class to presenter:
The last step is to create
TestContextProvider and add it’s usage in test:
Unconfied context. It means that coroutines execute at the same thread where other code running. It is similar to
Trampoline` scheduler in
Our last step is to pass
TestContextProvider to presenter constructor in test:
That’s all. Test will be green after next launch.
Talk is cheap. Show me the code. © Linus Torvalds