Migration Guide
Automated Migration
Robolectric provides an automated migration tool to help keep your test suite up to date with Robolectric API changes.
Migrating to 4.0
Project Configuration
Robolectric 4.0 requires Android Gradle Plugin 3.2 or greater.
Update the configuration in your module's build.gradle
/build.gradle.kts
file:
Add the following in your gradle.properties
file:
If you have dependencies on com.android.support.test
, switch them to androidx.test
; see
Migrate to AndroidX.
Deprecations
3.8 | 4.0 |
---|---|
ShadowApplication.getInstance() |
RuntimeEnvironment.application |
ShadowApplication.getLatestAlertDialog() |
ShadowAlertDialog.getLatestAlertDialog() |
ShadowApplication.getLatestDialog() |
ShadowDialog.getLatestDialog() |
ShadowApplication.getLatestPopupMenu() |
ShadowPopupMenu.getLatestPopupMenu() |
ShadowLooper.getShadowMainLooper() |
shadowOf(Looper.getMainLooper()) |
The automatic migration tool includes a migration to help with this.
The following attributes of the @Config
annotation are no longer supported when
using binary resources mode:
assetDir
andresourceDir
: follow the recommended file structure of your build system.manifest
: Robolectric always uses the merged manifest generated by the Android toolchain. If your test was using a custom manifest you'll need to adapt it to not rely on that.packageName
: to change your package name, override theapplicationId
in your build system.
Improper Use of Shadows
Prior to Robolectric 4.0, it was possible (but ill-advised) to get the shadow for an Android
framework object and invoke framework methods there. This could result in unexpected behavior (e.g.,
code in overridden methods in subclasses wouldn't be called). Shadow implementation methods are now
marked protected
to guard against this. Always invoke framework methods directly on the Android
class.
3.8 | 4.0 |
---|---|
shadowOf(activity).finish(); |
activity.finish() |
ShadowSystemClock.currentTimeMillis(); |
System.currentTimeMillis() |
The automatic migration tool will fix most of these for you.
androidx.test
Robolectric 4.0 includes initial support for androidx.test
APIs. We strongly
recommend adding the latest version of androidx.test:core
as a test dependency and using those
APIs whenever possible rather than using Robolectric-specific APIs.
3.8 | 4.0 |
---|---|
RuntimeEnvironment.application |
ApplicationProvider.getApplicationContext() |
ShadowMotionEvent |
MotionEventBuilder |
Troubleshooting
Robolectric 4.0 replaces its old home-grown resource handling code with a direct adaptation of Android's resource handling code, using the full Android toolchain. This greatly improves fidelity to the behavior of a real Android device, but if your tests were relying on the quirks of the old code, you may need to fix your tests.
Some likely issues include:
android.view.InflateException: Binary XML file line #3: Failed to resolve attribute at index 17: TypedValue{t=0x2/d=0x7f01000e a=-1}
This happens when your Activity
is using a theme that lacks values
for certain attributes used by layouts. Make sure you've specified an appropriate theme for your
activities in your AndroidManifest
.
Migrating to 3.6
Previously, Robolectric's Display
and
DisplayMetrics
dimensions defaulted to 480×800px,
regardless of screen size and density. Now they match the requested configuration, which defaults to
320×470dp mdpi. Tests which rely on the old dimensions for layouts, pixel math, etc. can be
modified for new dimensions, or by pinning them to the old size:
@Config(qualifiers = "w480dp-h800dp")
.
3.5 | 3.6 |
---|---|
Shadow.newInstanceOf(Display.class) |
ShadowDisplay.getDefaultDisplay() |
Migrating to 3.4
Dependencies
Robolectric tests should now be compiled with Java 8 and Android API 26.
PackageManager
We've change PackageManager
simulation to follow the standard
Shadow pattern as with other framework classes. You can use
ShadowPackageManager
where you previously used
RobolectricPackageManager
.
3.3 (was @Deprecated ) |
3.4 |
---|---|
org.robolectric.res.builder.RobolectricPackageManager |
ShadowPackageManager |
RuntimeEnvironment.getRobolectricPackageManager() |
shadowOf(RuntimeEnvironment.application.getPackageManager()) |
If you were using RuntimeEnvironment.setRobolectricPackageManager()
to install a custom
PackageManager
, you should move your custom behavior to a subclass of
ShadowApplicationPackageManager
and install it as a
shadow (using @Config
and possibly
@Implements(inheritImplementationMethods = true)
) instead.
ActivityController.attach()
The deprecated and redundant attach()
method has been removed from
ActivityController
,
FragmentController
, and
ServiceController
. To migrate, remove calls to this method.
Other Stuff
- Because
SharedPreferences
now uses real Android framework code, Mockito mocks and spies can lead to tests hanging. Rather than spying onSharedPreferences
, directly assert against its state.
Migrating to 3.3
Moved classes
To simplify classloader logic and cleanup packages, some classes have moved. The old class locations
are @Deprecated
and will be removed in 3.4.
3.2 (now @Deprecated ) |
3.3 |
---|---|
org.robolectric.internal.Shadow |
org.robolectric.shadow.api.Shadow |
org.robolectric.internal.ShadowExtractor.extract() |
org.robolectric.shadow.api.Shadow.extract() |
org.robolectric.util.ActivityController |
org.robolectric.android.controller.ActivityController |
org.robolectric.util.ContentProviderController |
org.robolectric.android.controller.ContentProviderController |
org.robolectric.util.FragmentController |
org.robolectric.android.controller.FragmentController |
org.robolectric.util.IntentServiceController |
org.robolectric.android.controller.IntentServiceController |
org.robolectric.util.ServiceController |
org.robolectric.android.controller.ServiceController |
org.robolectric.util.AccessibilityUtil |
org.robolectric.android.AccessibilityUtil |
org.robolectric.util.ApplicationTestUtil |
org.robolectric.android.ApplicationTestUtil |
org.robolectric.res.builder.StubPackageManager |
org.robolectric.android.StubPackageManager ⚠️ |
org.robolectric.res.builder.XmlResourceParserImpl |
org.robolectric.android.XmlResourceParserImpl ⚠️ |
org.robolectric.internal.fakes.RoboCharsets |
org.robolectric.android.fakes.RoboCharsets ⚠️ |
org.robolectric.internal.fakes.RoboExtendedResponseCache |
org.robolectric.android.fakes.RoboExtendedResponseCache ⚠️ |
org.robolectric.util.concurrent.RoboExecutorService |
org.robolectric.android.util.concurrent.RoboExecutorService ⚠️ |
⚠️ Only use these classes if you really need too
PackageManager
We have begun the process of switching from using a subclass of
PackageManager
towards PackageManager
being implemented by a
standard shadow, as we do for the rest of the framework. This is for a number of reasons:
- It is more consistent with the way other framework code is handled.
- A shadow will allow users' tests to build against any version of Android.
- Switching to a shadow will allow us to defer parsing the manifest until the test or code under
test makes calls to the
PackageManager
.
This should all be backwards compatible for the 3.3 release, but now you can start migrating your code.
Before, the Robolectric class DefaultPackageManager
implemented all PackageManager
functionality. If you wanted to change any of its behavior, you'd extend DefaultPackageManager
(or
StubPackageManager
) and override whichever methods you liked. Test-related setup was achieved by
calling RuntimeEnvironment.getRobolectricPackageManager()
, which had extra methods for modifying
its behavior.
As of 3.3, Robolectric uses the normal Android ApplicationPackageManager
, and shadows all of its
methods, causing it to delegate to an instance of DefaultPackageManager
, which works as before.
You can still replace it with your own subclass of PackageManager
if you like, but that's
deprecated. Instead of doing that, put your custom behavior in a subclass of
ShadowApplicationPackageManager
. For test-related
setup, you can still access it through RuntimeEnvironment.getRobolectricPackageManager()
, but you
should start using shadowOf(PackageManager)
instead. Note
that we've implemented quite a bit more of PackageManager
, so you might not need any custom code
any longer.
Starting with 3.4, DefaultPackageManager
will be removed and its functionality will be moved into
ShadowApplicationPackageManager
. In general, we recommand using Android Framework APIs where
possible.
3.2 (now @Deprecated ) |
3.3 |
---|---|
RobolectricPackageManager rpm = RuntimeEnvironment.getRobolectricPackageManager(); |
ShadowPackageManager shadowPackageManager = shadowOf(context.getPackageManager()); |
PackageManager packageManager = RuntimeEnvironment.getPackageManager(); |
PackageManager packageManager = context.getPackageManager(); |
RuntimeEnvironment.setRobolectricPackageManager(customPackageManager); |
Use a custom shadow instead! See below. |
Replace subclasses of DefaultPackageManager
by a custom shadow (and be a good citizen by
contributing your enhancements upstream 🙂):
If you are using a custom subclass of DefaultPackageManager
to implement functionality missing in
Robolectric, check again as part of this work we've added support for a bunch more widely-used
PackageManager
features, and it might be now possible to completely remove your custom subclass.
Deprecated Classes & Methods
3.2 (now @Deprecated ) |
3.3 |
---|---|
org.robolectric.res.builder.RobolectricPackageManager |
org.robolectric.shadows.ShadowPackageManager |
RuntimeEnvironment.getRobolectricPackageManager() |
shadowOf(RuntimeEnvironment.application.getPackageManager()) |
shadowOf(imageView).getImageResourceId() |
shadowOf(imageView.getDrawable) .getCreatedFromResId() |
shadowOf(notification).getProgressBar().isIndeterminate() |
shadowOf(notification) .isIndeterminate() |
The following methods and classes are deprecated will be removed in 3.4:
RuntimeEnvironment.getPackageManager()
RuntimeEnvironment.getRobolectricPackageManager()
RuntimeEnvironment.setRobolectricPackageManager()
DefaultPackageManager
StubPackageManager
RobolectricPackageManager
New Gradle integration
Starting with Robolectric 3.3 and Android Studio 3.0 alpha 5, we've included better integration with
the tool chain. Resources, assets and AndroidManifest.xml
are treated as first-class citizens and
processed by the build system for correctness, performance and stability between releases. Read
more here.
Migrating to 3.2
Programmatic Configuration
If you were providing custom configuration by subclassing and overriding methods on
RobolectricTestRunner
, you'll need to make some changes.
RobolectricTestRunner.getConfigProperties()
has moved to
ConfigMerger.getConfigProperties(String)
. But what
you probably actually want to do is override
RobolectricTestRunner.buildGlobalConfig()
.
Old code
New code
Package-Level Configuration
If you are using a robolectric.properties
file to
configure all tests, the expected location of the file has been changed.
3.1 | 3.2 |
---|---|
src/test/resources/robolectric.properties |
src/test/resources/your/package/robolectric.properties |
Migrating to 3.1
Changes
- To construct an Android components such as an
Activity
, aService
or aContentProvider
, you must now use the Robolectric APIs such asRobolectric.buildActivity()
,Robolectric.buildService()
, orRobolectric.buildContentProvider()
, or the correspondingsetup*()
methods; you should not create new instances of these classes yourself. Calling these methods will create an instance of the component and attach its baseContext
. This is now necessary as we've removed code shadowingContext
andContextWrapper
in favor of using real framework code to improve fidelity.
- We've removed shadow methods where they duplicate the functionality of the Android APIs. In general, prefer calling Android framework APIs over Robolectric shadows where possible.
3.0 | 3.1 |
---|---|
ShadowApplication.getInstance().getContentResolver() |
RuntimeEnvironment.application .getContentResolver() |
ShadowApplication.getInstance().getPackageManager() |
RuntimeEnvironment.application .getPackageManager() |
ShadowApplication.getInstance().getResources() |
RuntimeEnvironment.application .getResources() |
ShadowApplication.getInstance().getString() |
RuntimeEnvironment.application .getString() |
ShadowApplication.getInstance().resetResources() |
RuntimeEnvironment.application .resetResources() |
ShadowApplication.getInstance().getAssets() |
RuntimeEnvironment.application .getAssets() |
ShadowPreferenceManager.getDefaultSharedPreferences() |
PreferenceManager.getDefaultSharedPreferences() |
shadowOf(shadowOf(notification).getStyle()).getSummaryText() |
shadowOf(notification) .getContentText() |
RoboMenu
now requires aContext
passed into its constructor. Previously it was internally usingRuntimeEnvironment.application
which you can use as a sensible default..equals()
and.hashCode()
methods have been removed from shadows to stop them incorrectly providing an alternative equality of the shadowed object. For example,Intent.equals()
now behaves as the framework method. Instead of relying on a generically shadowedequals()
method with a vague equality rule, prefer to make assertions on specific fields of interest to the test. We recommend usingsquare/assertj-android
to make assertions clear.- Custom shadows now require the
public
access modifier on methods in the shadow class.
3.1.1 Changes
RoboAttributeSet
is deprecated and uses should be replaced withRobolectric.buildAttributeSet()
.RobolectricGradleTestRunner
is deprecated and uses should be replaced withRobolectricTestRunner
.
Migrating to 3.0
New Features
- Support for API 19 (KitKat)
- Support for API 21 (Lollipop)
- Custom test runner for Gradle / Android Studio:
Major Changes
2.4 | 3.0 |
---|---|
Robolectric.application |
RuntimeEnvironment.application |
Robolectric.shadowOf |
Shadows.shadowOf |
Robolectric.Reflection.setFinalStaticField |
ReflectionHelpers.setStaticField |
org.robolectric.Robolectric.<xxx>Looper |
org.robolectric.shadows.ShadowLooper.<xxx>Looper |
org.robolectric.Robolectric.getBackgroundScheduler |
org.robolectric.Robolectric.getBackgroundThreadScheduler |
org.robolectric.Robolectric.runBackgroundTasks |
org.robolectric.Robolectric.getBackgroundThreadScheduler().advanceBy(0) (also org.robolectric.Robolectric.flushBackgroundThreadScheduler will run delayed background tasks too) |
org.robolectric.Robolectric.getUiThreadScheduler |
org.robolectric.Robolectric.getForegroundThreadScheduler |
org.robolectric.Robolectric.runUiThreadTasks |
org.robolectric.shadows.ShadowLooper.runUiThreadTasks |
org.robolectric.Robolectric.runUiThreadTasksIncludingDelayedTasks |
org.robolectric.shadows.ShadowLooper.runUiThreadTasksIncludingDelayedTasks or org.robolectric.Robolectric.flushForegroundThreadScheduler |
org.robolectric.Robolectric.getShadowApplication |
org.robolectric.shadows.ShadowApplication.getInstance |
FragmentTestUtil.startFragment (v4/v11) |
SupportFragmentTestUtil.startFragment (v4) / FragmentTestUtil.startFragment (v11) |
org.robolectric.tester.android.view.TestMenuItem |
org.robolectric.fakes.RoboMenuItem |
ActivityController.of |
Robolectric.buildActivity |
org.robolectric.Config.properties |
robolectric.properties |
@Config(emulateSdk=...) / @Config(reportSdk=...) |
@Config(sdk=...) |
org.robolectric.shadows.ShadowHandler |
org.robolectric.shadows.ShadowLooper |
org.robolectric.shadows.ShadowSettings.SettingsImpl |
org.robolectric.shadows.ShadowSettings.ShadowSystem |
Robolectric.packageManager = instance |
RuntimeEnvironment.setRobolectricPackageManager(instance) |
org.robolectric.res.builder.RobolectricPackageManager changed from class to interface |
org.robolectric.res.builder.DefaultPackageManager |
org.robolectric.shadows.ShadowMenuInflater |
? |
org.robolectric.Robolectric.clickOn |
org.robolectric.shadows.ShadowView.clickOn |
Robolectric.shadowOf_
has been removed. Similar functionality exists inShadowExtractor.extract
.
Modules
Note
Shadows for non-core Android classes have moved out of the main Robolectric module. If you want to use those shadows, you'll need to include the requisite module.
org.robolectric:robolectric
Main "core" module for Robolectric 3.0.
Some of the shadows in Robolectric have been split out into separate modules to reduce the number of transitive dependencies imposed on projects using Robolectric. If you want to use any of these shadows, add the needed artifacts below to your build.
org.robolectric:shadows-support-v4
Shadows for classes in the Android support-v4
library.
org.robolectric:shadows-httpclient
Shadows for classes in Apache HTTP client. This includes methods like
Robolectric.getLatestSentHttpRequest
. These methods have moved to
FakeHttp.getLatestSentHttpRequest
.
org.robolectric:shadows-maps
Shadows for classes in Google Maps.