You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I found the following recommendation in various issues about using mocking frameworks for mocking Android classes like Activity/Context/etc.:
You should never mock Context objects using mocking frameworks. You should only be using Robolectric APIs to customize the behavior of Android classes. At Google mocking objects like Context, Activity, etc.. are banned.
Moreover, when any Android related class is used in test without Robolectric runner, the following exception fails the test:
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.RuntimeException: Method isEmpty in android.text.TextUtils not mocked. See https://developer.android.com/r/studio-ui/build/not-mocked for details. [in thread "Test worker"]
at android.text.TextUtils.isEmpty(TextUtils.java)
...
@bacecek It's not recommended using mock with Robolectric together. You can only use mock for one test file, for example mocking Activity, Context by yourself. You can only use Robolectric for your one test file by leveraging Robolectric's fake implementations of Android Frameworks. But it's not allowed/recommended to use them together as they use similar mechanism to modify class not and generate extra code for mocking purpose or shadow purpose, and sometimes they have conflicted with each other.
It is generally OK to mock Android objects, but there are a certain set of them that I would not recommend mocking. They are banned from being mocked internally at Google. These are the very large, complex classes like Context, Fragment, Resources, View, Activity, Application, etc..
Let's take Context for example. It's a very very complex class with hundreds of methods, many of which are @hide API, so these hidden methods are only invoked by other classes in the Android framework.
There are a lot of Android classes that take Context as a parameter. One I dealt with today was ViewConfiguration.get(Context), which builds a ViewConfiguration given the Context.
Let's say you are using a mock Context when calling ViewConfiguration.get(Context). You would have to implement:
Context.getResources()
A ton of methods on the Resources object returned by Context.getResources()
Context.getDisplayId() - this is a hidden @hide method
Now let's say that the new Version of Android introduced some new properties in ViewConfiguration, and some of those are derived from other methods in Context. You will now have to update the Context mock to try to return sensible values for those.
So you will typically feel the pain when you update the SDK level used in Robolectric tests.
Perhaps for a small development team this would not be a large burden. But at scale, for a company like Google, multiply these issues by hundreds of apps and thousands of developers, and updating the Android SDK becomes a very large challenge.
If people standardize on using Context objects built in Robolectric, there is a single place that needs to be changed if there are incompatibilities.
I found the following recommendation in various issues about using mocking frameworks for mocking Android classes like Activity/Context/etc.:
Unfortunatelly, I've not found this recommendation in Android open source projects:
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:docs/testing.md
https://cs.android.com/android/platform/superproject/main
or this robolectric repo.
Moreover, when any Android related class is used in test without Robolectric runner, the following exception fails the test:
which points to the page https://developer.android.com/training/testing/local-tests#mocking-dependencies, where example shows that mocking
Context
is okay.Could someone explain why mocking Android classes is the a bad idea and why?
The text was updated successfully, but these errors were encountered: