Unit Testing in MVVM+Kotlin+DataBinding

Unit Testing in MVVM+Kotlin+Data Binding

I love Kotlin and MVVM. When I began writing the application with it here at 1mg, I instantly went, “Wow”! It’s clean, it’s easy to read (sometimes 😁) and helps you write better code. However, while writing tests, I encountered certain problems.

In this article, let us resolve some of the common issues that can be faced during mocking and unit testing our features.

Mockito Troubles: the Right Dependencies

  1. In Kotlin

org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class com.example.authentication.login.LoginRepository

Mockito cannot mock/spy because :
final class

Reason -

When Mockito mocks an object it extends the requested class to create an instance. However, all classes in Kotlin are final by default. The rule: “closed for modifications, open for extension” is baked into the language. So they can’t be extended.

Solution -

Either Replace your mockito-core gradle with the following:

testImplementation 'org.mockito:mockito-inline:latestVersion'

It is the configuration to make Mockito work with final classes.

Or

Use the Mockito extension mechanism by creating the file org.mockito.plugins.MockMaker in your test folder -

test/resources/mockito-extensions/org.mockito.plugins.MockMaker

Write this line in the file -

mock-maker-inline

2. Another problem was of AndroidSchedulers -

java.lang.ExceptionInInitializerError at io.reactivex.android.schedulers.AndroidSchedulers$1.call(AndroidSchedulers.java:35) at io.reactivex.android.schedulers.AndroidSchedulers$1.call(AndroidSchedulers.java:33) at io.reactivex.android.plugins.RxAndroidPlugins.callRequireNonNull(RxAndroidPlugins.java:70) at io.reactivex.android.plugins.RxAndroidPlugins.initMainThreadScheduler(RxAndroidPlugins.java:40) at io.reactivex.android.schedulers.AndroidSchedulers.<clinit>(AndroidSchedulers.java:32)

Reason -

Default Scheduler returned by AndroidSchedulers.mainThread() is an instance of HandlerScheduler which relies on Android dependencies which are not available to be instantiated on the JVM.

However, we want to override the default AndroidSchedulers.mainThread() scheduler and return an instance which does not have these Android dependencies and can be safely instantiated.

Solution -

Use RxAndroid’s RxAndroidPlugins class which provides some hooks for overriding RxAndroid’s schedulers.

3. Error while mocking Repository

private var loginRepository = mock<LoginRepository>()

After running the test, I saw the test failed as the actual repository was getting called.

Reason -

Here you can see, I am initializing the repository inside the ViewModel class, which means when I initialize my ViewModel class in Test, those mock repositories will get replaced with the actual implementation.

Solution -

Pass these repositories from Factory to the ViewModel, you will always get the same instance you want to get invoked.

ViewModelFactory: It’s a class that implements ViewModelProvider.Factory and it will create the ViewModel from a parameter .class.

In your ViewModel -

4. Error while mocking LiveData Observers -

private val mockObserver = mock<Observer<AuthenticationState>>

Error -

java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.

Solution -

When testing LiveData, InstantTaskExecutorRule is needed in addition to RxImmediateSchedulerRule if the class being tested has both background thread and LiveData.

Use this with RxImmediateSchedulerRule -

I hope I helped you with this article. If you have any questions, please let me know!

Originally published here.

If you liked this blog, hit the 👏 . Stay tuned for the next one!

--

--

--

India's most trusted consumer health platform.

Recommended from Medium

[ Flutter ] The shrinker may have failed to optimize the Java bytecode. Error

Introduction to Android’s CameraX With Java

Custom In-App Emoji Utility for Android

Android 开发技术周报 Issue#293

How we stay up to date with our dependencies

Detail Page Design using Jetpack Compose

Android Widgets in 2020 📱🤖

Flutter — How to check for rooted or jailbroken devices.

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
Niharika Arora

Niharika Arora

Googler since 2021 | Ex- Google Developer Expert, Android | Visit : https://thedroidlady.com/ to know more.

More from Medium

Android 102 : Why does dagger generate MembersInjector for us?

Kotlin/Gradle/JUnit starter project

Kotlin Coroutines [Part-2]

Kotlin Coroutines