Robolectric with Gradle: Resources not found
Solution 1
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!
Solution 2
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.
Comments
-
passy almost 4 years
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 theandroid
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
intest/
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 thecompileTestJava
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?
-
passy almost 11 yearsThis looks like a huge step into the right direction, thanks! The Robolectric testrunner is executing, however, I'm now getting a "android.content.res.Resources$NotFoundException: unknown resource xxx" when anything tries to access a resource. Full stacktrace here: gist.github.com/passy/255bbd42ada11ad5fba7
-
passy almost 11 yearsThis seems to come from the testrunner being unable to find the
AndroidManifest.xml
, which lies insrc/main
. I guess I could set those paths in the a RobolectricTestRunner subclass, but with Eclipse I would just set the working directory to the main project. Can I do that in the gradle file? -
user2457888 almost 11 years@passy Unfortunately I haven't seen that issue come up. However, you should be able to put your
AndroidManifest.xml
in the root of the project directory and override the manifest source set by doing something similar to this inbuild.gradle
:android { sourceSets { main { manifest.srcFile 'AndroidManifest.xml' } } }
Source: tools.android.com/tech-docs/new-build-system/user-guide -
passy almost 11 yearsThanks again, @user2457888. :) I set the
workingDir
inside thelocalTest
task tosrc/main
and now it finds theAndroidManifest.xml
and all resources. -
alex almost 11 yearsI have everything working from gradle, but the IDE complains because it can't find the imports. How did you add the dependencies to the project in the ide? Did you create a module? How did you configure it?
-
ligi almost 11 yearsthanks - that looks good - unfortunately I get "Could not find method testLocalCompile() for arguments [junit:junit:4.8.2] on project" - any Idea on how to solve this?
-
Mark almost 11 yearsI got this working, and merged with the "old" example from github.com/novoda/robolectric-plugin , and so was able to remove the duplicate dependency calls. I'm able to run it from the command line just fine. Getting Android Studio to see it, as alex mentioned, is a problem. I was able to set src/test/main as a root test folder - but the Studio can't find junit, robolectric, etc. test dependencies.
-
Mark almost 11 years@alex - I figured it out! Go into the module settings, in dependencies, add a new library, choose from maven, and add robolectric. Change the scope on it to compile. Works for now, although it might interfere if you're using instrumentationTest as well.
-
ebernie almost 11 years@Mark do you mind sharing how you were able to set src/test/main as a root test folder? If I configure this via the IDE, it keeps resetting itself to a non-src dir, presumably because it's not set in my build.gradle.
-
Mark almost 11 yearsYou right click on it, and mark it as test root - I forget the exact menu sequence. But you're right - it does keep resetting itself. It looks like there's no way to have it stick.
-
Thomas Kaliakos almost 11 yearsThis is really cool...but I have a project that I ported from Eclipse into Android Studio and therefore has the old folder structure: (Project folder/ src, res, libs, gen ...) . How would that affect the localTest and specifically the buildDir variable?
-
Maragues almost 11 yearsHi user2457888, could you upload a sample project to a public repo? I'm unable to compile the test project, I could really use some real code. Also, have you tested it for Gradle 0.5.+? Thanks!
-
Colin M. over 10 yearsI'm anxiously awaiting Jake's plugin to support resources split by buildType. Currently it can't seem to deal with that. Someone wrote a patch to fix this (a few months ago) but there's been no comments on it and has not been accepted. Until then, the method in the accepted answer is working.
-
Colin M. over 10 yearsAny idea how this could be updated to include the yet-to-be-standard aar format as a dependency? See my related issue here: stackoverflow.com/questions/21099754/…
-
Flame about 10 yearsSeems like Jake Wharton's plugin is now deprecated?
-
Saad Farooq about 10 yearsYes it is. There seems to be a flurry to move to the standard android test infrastructure. Robolectric is still helpful for some cases but I found it easier to manage the application so that most of my pure java classes are java library modules that are unit tested with junit and Android specific ones with the android test framework.
-
Colin M. over 9 yearsAnyone have luck modifying this method to work with flavors? When I add flavors, the testLocal fails not being able to find any of my classes, even though there's no classes needed from the flavors for the tests.
-
Cris over 5 yearsBoth old and new answer reference deprecated plugins