androidandroid-gradle-pluginandroid-resourcesrobolectricrobolectric-gradle-plugin

Robolectric with test.R.java


I've got a library project using robolectric 3.0 at API21, with com.android.tools.build:gradle:1.3.1.

I want to use test resources (as if under src/androidTest/res/...), namely com.mypackage.test.R.java (as opposed to com.mypackage.R.java for production) in robolectric tests.

What I have so far:

Directory structure is

src/
  main/
    java
    res
  test/
    java
    // no res here because it's not picked up 
  androidTest/
    res    // picked up by androidTest build variant to generate test.R.java

Then in build.gradle:

android {
  compileSdkVersion 21
  buildToolsVersion = "22.0.1"

  defaultConfig {
    minSdkVersion 15
    targetSdkVersion 21
  }

  sourceSets {
    test {
        java {
            srcDir getTestRJavaDir()
        }
    }
  }
}

def private String getTestRJavaDir(){
  def myManifestRoot = (new XmlParser()).parse("${project.projectDir}/src/main/AndroidManifest.xml")
  def myPackageNamespace = myManifestRoot.@package
  def myPackagePath = myPackageNamespace.replaceAll("\\.", "/")

  return "${project.buildDir}/generated/source/r/androidTest/debug/${myPackagePath}/test"
}

afterEvaluate { project ->
  [tasks.compileDebugUnitTestSources, tasks.compileReleaseUnitTestSources]*.dependsOn("compileDebugAndroidTestSources")
}

My tests now successfully compile with test.R.java.

However, at runtime, they fail because robolectric now fails to find my asset files, because they are now located in ${project.buildDir}/intermediates/assets/androidTest/debug whereas previously they were in ${project.buildDir}/intermediates/assets/debug. My suspicion is that robo would also fail to find resource files because they have also been moved under the androidTest (build variant?) directory.

So two questions: 1) is there a better way to do this? 2) if there isn't, how can I tell robolectric where to look for the asset files?

I've tried @Config(assetDir="build/intermediates/assets/androidTest/debug") and @Config(assetDir="../build/intermediates/assets/androidTest/debug") to no avail.


Solution

  • You can create a custom roboletric test runner like:

    public class CustomRobolectricGradleTestRunner extends RobolectricGradleTestRunner {
    
        public CustomRobolectricGradleTestRunner(Class<?> klass) throws InitializationError {
            super(klass);
        }
    
        // Fix for the NotFound error with openRawResource()
        @Override
        protected AndroidManifest getAppManifest(Config config) {
            String manifest = "src/main/AndroidManifest.xml";
            String res = String.format("../app/build/intermediates/res/merged/%1$s/%2$s", BuildConfig.FLAVOR, BuildConfig.BUILD_TYPE);
            String asset = "src/test/assets";
            return new AndroidManifest(Fs.fileFromPath(manifest), Fs.fileFromPath(res), Fs.fileFromPath(asset));
        }
    }
    

    In the variable asset you can define something like "../build/intermediates/assets/androidTest/debug"