Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Robolectric with Gradle: Resources not found

I'm trying to run my Robolectric tests together with the new Gradle Android build system, but I'm stuck at accessing the resources of my main project.

I split the build into two separate projects to avoid conflicts between the java and the android gradle plugins, so the directory structure looks roughly like this:

. ├── build.gradle ├── settings.gradle ├── mainproject │   ├── build │   │   ├── classes │   │   │   └── debug │   ├── build.gradle │   └── src │       └── main │           ├── AndroidManifest.xml │           └── ... └── test     ├── build.gradle     └── src         └── test             └── java                 └── ...                     └── test                         ├── MainActivityTest.java                         ├── Runner.java                         ├── ServerTestCase.java                         └── StatusFetcherTest.java 

My build.gradle in test/ currently looks like this:

buildscript {     repositories {         mavenCentral()     }      dependencies {         classpath 'com.stanfy.android:gradle-plugin-java-robolectric:2.0'     } }  apply plugin: 'java-robolectric'  repositories {...}  javarob {     packageName = 'com.example.mainproject' }  test {     dependsOn ':mainproject:build'     scanForTestClasses = false     include "**/*Test.class"     // Oh, the humanity!     def srcDir = project(':mainproject').android.sourceSets.main.java.srcDirs.toArray()[0].getAbsolutePath()     workingDir srcDir.substring(0, srcDir.lastIndexOf('/')) }  project(':mainproject').android.sourceSets.main.java.srcDirs.each {dir ->     def buildDir = dir.getAbsolutePath().split('/')     buildDir =  (buildDir[0..(buildDir.length - 4)] + ['build', 'classes', 'debug']).join('/')      sourceSets.test.compileClasspath += files(buildDir)     sourceSets.test.runtimeClasspath += files(buildDir) }  dependencies {         testCompile group: 'com.google.android', name: 'android', version: '4.1.1.4'     testCompile group: 'org.robolectric', name: 'robolectric', version: '2.0-alpha-3'     ... } 

The evil classpath hackery allows me to access all classes of my main project, except for R, which exists as .class file in the build directory, but raises this error during the compileTestJava task:

/.../MainActivityTest.java:16: error: cannot find symbol                 final String appName = activity.getResources().getString(R.string.app_name);                                                                           ^   symbol:   variable string   location: class R 1 error :test:compileTestJava FAILED 

There must be a better way to execute Robolectric tests with the new build system, right?

(Full source of the app)

like image 964
passy Avatar asked May 20 '13 12:05

passy


2 Answers

I was running across this same issue and this is what I came up with. Instead of creating a separate project for the tests, I created a source set for the Robolectric tests and added a new task that "check" would depend on. Using some of the code from your question, here are the relevant bits of the (working) build file:

apply plugin: 'android'  sourceSets {     testLocal {         java.srcDir file('src/test/java')         resources.srcDir file('src/test/resources')     } }  dependencies {     compile 'org.roboguice:roboguice:2.0'     compile 'com.google.android:support-v4:r6'      testLocalCompile 'junit:junit:4.8.2'     testLocalCompile 'org.robolectric:robolectric:2.1'     testLocalCompile 'com.google.android:android:4.0.1.2'     testLocalCompile 'com.google.android:support-v4:r6'     testLocalCompile 'org.roboguice:roboguice:2.0' }  task localTest(type: Test, dependsOn: assemble) {     testClassesDir = sourceSets.testLocal.output.classesDir      android.sourceSets.main.java.srcDirs.each { dir ->         def buildDir = dir.getAbsolutePath().split('/')         buildDir =  (buildDir[0..(buildDir.length - 4)] + ['build', 'classes', 'debug']).join('/')          sourceSets.testLocal.compileClasspath += files(buildDir)         sourceSets.testLocal.runtimeClasspath += files(buildDir)     }      classpath = sourceSets.testLocal.runtimeClasspath }  check.dependsOn localTest 

I've included my dependencies block to point out that in order for me to get this up and going, I had to repeat all of my compile dependencies in my custom testLocal source set.

Running gradle testLocal builds and runs just the tests inside of src/test/java, while running gradle check runs these tests in addition to those in the default android instrumentTest source set.

Hope this helps!

like image 200
user2457888 Avatar answered Sep 23 '22 16:09

user2457888


Update: Jake Wharton just announced the gradle-android-test-plugin. You can find it at https://github.com/square/gradle-android-test-plugin

It seems to be pretty streamlined, especially if you plan to use robolectric.


Old Answer Below

The robolectric-plugin looks promising.

The sample build.gradle file they provide is :

buildscript {     repositories {         mavenCentral()         maven {             url "https://oss.sonatype.org/content/repositories/snapshots"         }     }     dependencies {         classpath 'com.android.tools.build:gradle:0.4.2'         classpath 'com.novoda.gradle:robolectric-plugin:0.0.1-SNAPSHOT'     } }  apply plugin: 'android' apply plugin: 'robolectric'  repositories {     mavenCentral()     mavenLocal()     maven {         url "https://oss.sonatype.org/content/repositories/snapshots"     } }  dependencies {     //compile files('libs/android-support-v4.jar')      // had to deploy to sonatype to get AAR to work     compile 'com.novoda:actionbarsherlock:4.3.2-SNAPSHOT'      robolectricCompile 'org.robolectric:robolectric:2.0'     robolectricCompile group: 'junit', name: 'junit', version: '4.+' }  android {     compileSdkVersion 17     buildToolsVersion "17.0.0"      defaultConfig {         minSdkVersion 7         targetSdkVersion 17     } } 

It doesn't seem to work with the Android Gradle plugin version 0.5 but maybe it will soon.

like image 35
Saad Farooq Avatar answered Sep 23 '22 16:09

Saad Farooq