Robolectric has reach a big milestone recently: V3-rc2, so it was time
to upgrade all my personal projects.
With the new release, the team has introduced new concepts and new APIs (and removed and renamed others). In most cases, I find the new API and structure much more readable, and generally like it.
But as a long time user of Robolectric, it also means that I have a lot of code to refactor.
Note: all code in this post is Public Domain as described in CC0.
First, to make things clear, if it wasn’t worth the hassle, I would not upgrade to v3, but this new version comes with a lot of nice improvements
and Robolectric, in general, is awesome beyond words.
Second, let’s get to the migration guide:
Gradle stuff
You no longer need the Robolectric Gradle plugin. So just remove
classpath 'org.robolectric:robolectric-gradle-plugin'
from build.gradle.
Some developers had used a hack to get Robolectric tests navigable in Android Studio:
and/or
You don’t need those anymore.
Any specific Robolectric settings should also be removed, since we are not using the Robolectric Gradle Plugin anymore. Remove this:
With Android Gradle Plugin v1.1.0 there is a built-in support for unit-test (using mockableAndroidJar), so we no longer need to setup
Robolectric as androidTestCompile.
Change androidTestCompile('org.robolectric:robolectric:2.4')
to testCompile 'org.robolectric:robolectric:3.0-rc2'
DO NOT USE com.squareup:fest-android:1.0.8
. If you have it in your testCompile
be sure to remove it. There is a conflict between
it and Robolectric which causes all Fragment/Activity related unit-tests to fail with NoSuchMethodError
.
If you have to use com.squareup:fest-android:1.0.8
, then remove support-v4
from it:
TestRunner
You have probably used @RunWith(RobolectricTestRunner.class)
in your classes. Switch to RobolectricGradleTestRunner
, but also add a @Config
annotation, and point to your app’s BuildConfig
class:
This is enough, but I opted to a different approach: a custom test-runner that sets the Robolectric configuration:
This test-runner will set the app’s SDK level to 21 (since Robolectric does not support anything higher than that, right now), and will
set the constants
value to the app’s BuildConfig class.
API and Behavioral Changes
Entry Points
Robolectric.application
does not exist anymore. From now on useRuntimeEnvironment.application
.Robolectric.shadowOf()
does not exist anymore. From now on useShadows.shadowOf()
.Robolectric.getShadowApplication()
does not exist anymore. From now on useShadowApplication.getInstance()
.
Activity life-cycle management
Robolectric lets you manage the life cycle of the activity using it’s ActivityController
. This is still there, but there are two
additions:
ActivityController.postCreate()
was added.ActivityController
now has a newsetup
method which is a shorthand forcreate().start().postCreate(null).resume().visible().get()
.- and another shorthand was added
Robolectric.setupActivity(Class<T extends Activity>)
.
Quite useful.
Add-On Modules
Robolectric was broken up to modules; the main library will only include Shadows for the main Android framework classes, and anything else (support library, maps, etc) is served as an Add-On Module.
I don’t have much to say about that, other than: if you want a Shadow of a class that is part of an external library (for example, support-v4’s LocalBroadcastManager
), be sure to include the right Add-On (for example testCompile 'org.robolectric:shadows-support-v4'
). You can access the Shadow using the Add-On’s specific Shadows
entry-point (for completeness: org.robolectric.support.v4.Shadows
).
Missing stuff
This is what I’ve found so far:
IntentFilter
will not doequals
correctly anymore. I guess that this is due to some cleanup, which resulted in Shadows to be removed. I used a new static method to calculatematch
: I use Mockito a lot and needed a Matcher too.
Replaced stuff
This is what I’ve found so far:
TestCursor
was replaced withRoboCursor
, which is an improved version of it. This is a great addition.- UI Thread is now called ForegroundScheduler, which means that
Robolectric.runUiThreadTasksIncludingDelayedTasks()
is now calledRobolectric.flushForegroundScheduler();
Other
This is what I’ve found so far:
Time
now respects the default time-zone! So make sure you set it correctly in your unit-tests (most probably in the@Before
method): Also, note thatTime
is Deprecated with API-22, so you might want to refactor to useGregorianCalendar
. But, no pressure.- Robolectric now supports API level 21! This means that if you assumed in your tests that you are running on an API level 18 (which was the highest/default API level for Robolectric v2.4), this is no longer the case! The default API level is 21!
@Config(emulateSdk = 18)
or@Config(qualifiers = "v19")
are your best friends there. And don’t forget to add the missing unit-test for API levels higher than that. - Since the
robolectric
gradle closure is removed, any special Java related configuration (e.g.,maxHeapSize
) should be moved toandroid->testOptions->unitTests.all
closure. Something like this:
Please share your tips and tricks for migrating in the comments! I’ll update this post as things coming in