New Android projects are built with Gradle
There is a plugin for Gradle called gradle-android-test-plugin that will run unit tests relying on Robolectric and compile the results in a test report. The following will describe how to change your build.gradle to set this up. First, pitfalls along the way will be shown, followed by a working build.gradle configuration. Finally, a few tweaks have to be made to integrate this properly with Android Studio.Pitfalls and how to work around them
These are problems I encountered when trying to set up the gradle-android-test-plugin and how to circumvent them.Gradle cannot determine dependencies
* What went wrong: Could not determine the dependencies of task ':MyApp:testDefaultFlavorDebug'. > A base directory must be specified in the task or via a method argumentSolution: Use 0.9.1-SNAPSHOT version of the gradle-android-test-plugin., it fixes this problem.
Robolectric: Resource path restrictions
java.lang.IllegalArgumentException: Resource path must end in "/res" at org.robolectric.res.PackageResourceLoader.<init>(PackageResourceLoader.java:20) at org.robolectric.res.PackageResourceLoader.<init>(PackageResourceLoader.java:11)Solution: Use 2.3-SNAPSHOT version of Robolectric, it fixes this restriction on the path name.
Robolectric: No KitKat
java.lang.UnsupportedOperationException: Robolectric does not support API level 19, sorry!Solution: As defined per SdkConfig.java, Roboelectric only supports SDKs 16 through 18. Change targetSdkVersion to 16, 17 or 18.
Summary of necessary changes to build.gradle
Your build.gradle has to be changed in quite a few places to set up gradle-android-test-plugin. Here's the condensed summary of theses changes:buildscript { repositories { maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } dependencies { classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.1-SNAPSHOT' } } apply plugin: 'android-test' repositories { maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } dependencies { testCompile 'junit:junit:4.10' testCompile 'org.robolectric:robolectric:2.3-SNAPSHOT' testCompile 'com.squareup:fest-android:1.0.+' }
Write a first unit test
Now you can create a unit test. Create a file in src/test/com.myapp.MyTest.java:package com.myapp; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import static org.junit.Assert.assertTrue; @RunWith(RobolectricTestRunner.class) public class MyTest { @Test public void testNumberOne() { assertTrue(false); } }Note that with Robolectric 2.3-SNAPSHOT you do not need RobolectricGradleTestRunner anymore, since it is integrated. When you now run ./gradlew test in your project, it should run that very unit test, which will -- by design -- fail:
com.myapp.MyTest > testNumberOne FAILED java.lang.AssertionError at MyTest.java:13
Integrating with Android Studio
So far, we have a working set up of Gradle, Robolectric and the gradle-android-test-plugin -- but only for the console. When we try to "Sync Project with Gradle Files" in Android Studio, the IDE will not pick up our newly created src/test folder and it will not provide content assist when writing code.This is because Android Studio expects test code to be in src/instrumentationTest, but luckily we can change that in build.gradle:
android { sourceSets.instrumentTest.setRoot('src/test') }Android Studio also cannot compile the test code because it misses dependencies. This is because it expects these dependencies to be defined in the configuration named instrumentTestCompile, whereas currently, we are using the testCompile configuration only. We have to add the dependencies defined earlier to the configuration Android Studio uses. This can even be achieved without repeating them, but by creating a copy, like so:
dependencies { instrumentTestCompile configurations.testCompile.dependencies }