Skip to content

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:

android {
    compileSdkVersion 28 // Or newer
    testOptions.unitTests.includeAndroidResources = true
}
android {
    compileSdkVersion = 28 // Or newer
    testOptions.unitTests.isIncludeAndroidResources = true
}

Add the following in your gradle.properties file:

android.enableUnitTestBinaryResources=true

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 and resourceDir: 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 the applicationId 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 on SharedPreferences, 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.

3.2 (now @Deprecated) 3.3
RobolectricPackageManager rpm = RuntimeEnvironment.getRobolectricPackageManager(); ShadowPackageManager shadowPackageManager
= shadowOf(context.getPackageManager());
PackageManager packageManager = RuntimeEnvironment.getPackageManager(); // Prefer Android Framework APIs where possible
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 🙂):

@Implements(value = ApplicationPackageManager.class, inheritImplementationMethods = true)
public class MyCustomPackageManager extends ShadowApplicationPackageManager {
}
@Implements(value = ApplicationPackageManager::class, inheritImplementationMethods = true)
class MyCustomPackageManager : ShadowApplicationPackageManager

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

public class MyTestRunner extends RobolectricTestRunner {
  @Override protected Properties getConfigProperties() {
    Properties props = new Properties();
    props.setProperty("sdk", "23");
    return props;
  }
}
class MyTestRunner : RobolectricTestRunner {
  override protected fun getConfigProperties(): Properties {
    val props = Properties()
    props.setProperty("sdk", "23")
    return props
  }
}

New code

public class MyTestRunner extends RobolectricTestRunner {
  @Override protected Config buildGlobalConfig() {
    return new Config.Builder().setSdk(23).build();
  }
}
class MyTestRunner : RobolectricTestRunner {
  override protected buildGlobalConfig(): Config {
    return Config.Builder().setSdk(23).build()
  }
}

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

Robolectric.buildService(MyService.class).create().get();
Robolectric.setupContentProvider(MyContentProvider.class);
Robolectric.buildService(MyService::class).create().get()
Robolectric.setupContentProvider(MyContentProvider::class)
  • 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 a Context passed into its constructor. Previously it was internally using RuntimeEnvironment.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 shadowed equals() method with a vague equality rule, prefer to make assertions on specific fields of interest to the test. We recommend using square/assertj-android to make assertions clear.
  • Custom shadows now require the public access modifier on methods in the shadow class.

3.1.1 Changes


Migrating to 3.0

New Features

  • Support for API 19 (KitKat)
  • Support for API 21 (Lollipop)
  • Custom test runner for Gradle / Android Studio:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class)
@RunWith(RobolectricGradleTestRunner::class)
@Config(constants = BuildConfig::class)

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 in ShadowExtractor.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.

testCompile 'org.robolectric:robolectric:3.0'
testCompile("org.robolectric: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.

testCompile 'org.robolectric:shadows-support-v4:3.0'
testCompile("org.robolectric:shadows-support-v4:3.0")

org.robolectric:shadows-httpclient

Shadows for classes in Apache HTTP client. This includes methods like Robolectric.getLatestSentHttpRequest. These methods have moved to FakeHttp.getLatestSentHttpRequest.

testCompile 'org.robolectric:shadows-httpclient:3.0'
testCompile("org.robolectric:shadows-httpclient:3.0")

org.robolectric:shadows-maps

Shadows for classes in Google Maps.

testCompile 'org.robolectric:shadows-maps:3.0'
testCompile("org.robolectric:shadows-maps:3.0")