The updated code can be found on GitHub: https://github.com/kvandermast/my-robolectric-app.
Changes to the build.gradle script
First of all, we updated the Gradle Build tools and the Robolectric Gradle Plugin.
... buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:1.2.3' classpath 'org.robolectric:robolectric-gradle-plugin:1.1.0' } } ...
The name of the plugin has changed from 'robolectric' to 'org.robolectric', so that needed to be updated too.
... apply plugin: 'com.android.application' apply plugin: 'org.robolectric' //used to be 'robolectric' ...
Next up was the dependencies block: we updated to the latest versions of Robolectric, jUnit and Butterknife. Note that we changed the "androidTestCompile" to "testCompile", and added the "androidTestCompile" for Robolectric (seems to be required to the code compiled in your Android Studio).
... // ================== TESTING LIBRARIES ====================== testCompile 'junit:junit:4.10' testCompile 'org.robolectric:robolectric:3.0-rc2' testCompile 'com.jakewharton:butterknife:6.1.0' androidTestCompile 'org.robolectric:robolectric:3.0-rc2' ...
The following section used to be the 'robolectric' task, which is now called "android.testOptions.unitTests.all".
... android.testOptions.unitTests.all { // configure the set of classes for JUnit tests include '**/*Test.class' //exclude '**/espresso/**/*.class' // configure max heap size of the test JVM maxHeapSize = "2048m" } ...
With these changes, you'll need to synch the project to get the latest libraries. With the upgrade from Robolectric 2.3 to 3.0, quite some changes were made to the library, resulting failed tests. The changes that were made are described in the following section.
Changes to tests
Using a custom RobolectricGradleTestRunnner class
We'll invoke a specific RobolectricTestRunnner which loads the AndroidManifest from the main project.package be.acuzio.mrta.test; import org.junit.runners.model.InitializationError; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.manifest.AndroidManifest; import org.robolectric.res.Fs; public class RobolectricGradleTestRunner extends RobolectricTestRunner { public RobolectricGradleTestRunner(Class testClass) throws InitializationError { super(testClass); } @Override protected AndroidManifest getAppManifest(Config config) { String manifestProperty = System.getProperty("android.manifest"); AndroidManifest manifest; if (config.manifest().equals(Config.DEFAULT) && manifestProperty != null) { String resProperty = System.getProperty("android.resources"); String assetsProperty = System.getProperty("android.assets"); manifest = new AndroidManifest(Fs.fileFromPath(manifestProperty), Fs.fileFromPath(resProperty), Fs.fileFromPath(assetsProperty)); } else { String myAppPath = RobolectricGradleTestRunner.class.getProtectionDomain() .getCodeSource() .getLocation() .getPath(); String manifestPath = myAppPath + "../../../src/main/AndroidManifest.xml"; String resPath = myAppPath + "../../../src/main/res"; String assetPath = myAppPath + "../../../src/main/assets"; manifest = createAppManifest(Fs.fileFromPath(manifestPath), Fs.fileFromPath(resPath), Fs.fileFromPath(assetPath)); } return manifest; } }
Changing the test configuration
The new version of Robolectric supports API levels higher than 18 (woot!). Unfortunately, something isn't quite working as expected on the new Robolectric version (you'll get ResourceNotFound exceptions, which only occur after upgrading from version 2.4 to 3.0). To fix this, pass the BuildConfig class (from your application module, not your test module) in the constants configuration.... @Config(emulateSdk = 21, constants = be.acuzio.mrta.BuildConfig.class) @RunWith(RobolectricGradleTestRunner.class) public class WidgetActivityTest { ...
Changing the Shadows
In version 2.4 we frequently used the Robolectric.getShadowApplication() method to fetch the Shadowed Application-class, e.g.... @Config(emulateSdk = 18) @RunWith(RobolectricTestRunner.class) public class MyBroadcastReceiverTest { ... /** * Let's first test if the BroadcastReceiver, which was defined in the manifest, is correctly * load in our tests */ @Test public void testBroadcastReceiverRegistered() { List<ShadowApplication.Wrapper> registeredReceivers = Robolectric.getShadowApplication().getRegisteredReceivers(); Assert.assertFalse(registeredReceivers.isEmpty()); boolean receiverFound = false; for (ShadowApplication.Wrapper wrapper : registeredReceivers) { if (!receiverFound) receiverFound = MyBroadcastReceiver.class.getSimpleName().equals( wrapper.broadcastReceiver.getClass().getSimpleName()); } Assert.assertTrue(receiverFound); //will be false if the container did not register the broadcast receiver we want to test } ...
But in version 3.0, we need to fetch it from the ShadowApplication class, insteadof the Robolectric class:
... @Config(emulateSdk = 21, constants = be.acuzio.mrta.BuildConfig.class) @RunWith(RobolectricGradleTestRunner.class) public class MyBroadcastReceiverTest { static { // redirect the Log.x output to stdout. Stdout will be recorded in the test result report ShadowLog.stream = System.out; } private ShadowApplication application; @Before public void setup() { this.application = ShadowApplication.getInstance(); } /** * Let's first test if the BroadcastReceiver, which was defined in the manifest, is correctly * load in our tests */ @Test public void testBroadcastReceiverRegistered() { //used to be:... registeredReceivers = Robolectric.getShadowApplication().getRegisteredReceivers(); List<ShadowApplication.Wrapper> registeredReceivers = this.application.getRegisteredReceivers(); Assert.assertFalse(registeredReceivers.isEmpty()); ...
Running the tests
With Android Studio 1.2.1.1 (as of 1.1 I believe), it is - finally - possible to run the tests from within the IDE. Previously we needed to run the test from the console like so:$ ./gradlew testDebug
Which worked perfectly, unless you had a lot of test and little patience to seem them executed one by one.
You can now use the "Unit test" Test Artificat in the build variants.
Running a test is now quite easy, just press "CTRL+R" when in the Test Class, or select "Run '