BrantApps
BrantApps

Reputation: 6472

Robolectric and Android Studio 1.1.0 and library testing

I am having trouble getting my Robolectric unit tests to run under the experimental AS 1.1 unit testing variant. The error I am getting is shown below;

java.lang.NoClassDefFoundError: com/my/app/R$string
    at com.my.app.MoneyFormatter.formatDealMessage(MoneyFormatter.java:63)
    ...
Caused by: java.lang.ClassNotFoundException: com.my.app.R$string
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at org.robolectric.bytecode.AsmInstrumentingClassLoader.loadClass(AsmInstrumentingClassLoader.java:100)
    ... 46 more

I retrieve this error by executing from the command line at the root (app-name in Snippet1) the command;

./gradlew core:library:test

This approach works in Android Studio 1.1 without unit testing enabled and using the android gradle tooling at v1.0 (com.android.tools.build:gradle:1.0.0).

Project configuration

My project has a complex structure as prescribed below;

app-name
 |
 |->app
    |->src
       |-> androidTest // Espresso helper classes reside here
       |-> androidTestFlavour1 // Espresso int tests relating to 'flavour 1' 
       |-> androidTestFlavour2 // Espresso int tests relating to 'flavour 2'
       |-> flavour1
       |-> flavour2
       |-> main
           + AndroidManifest.xml // Manifest for apps
       |-> testFlavour1 // Robolectric unit tests for flavour 1
       |-> testFlavour2 // Robolectric unit tests for flavour 2
 |->core
       |->library
           |-> src
              |-> main // Library code resides here
                  + AndroidManifest.xml
              |-> test // Robolectric unit tests for library
 +gradle
 +gradlew
 +settings.gradle
 +local.properties

Snippet 1: Project schematic

I have followed various pieces of advice from Pivotal Labs themselves and numerous other home-brew alternatives with no success.

What is the error saying and what do I need to change to put it right?

Update: So having inspected the classpath being used to run the tests I noted the following library paths;

Neither of these directories contain the generated R$string.class file hence the exception. The directory containing the generated 'R' files include the debug and release build types of the application. So;

This indicates that a part of the build process is missing adding the "debug" or "release" build type resources. This also backs-up the behaviour whereby pure-Java test cases (that only rely on the classes.jar) work fine.

Upvotes: 4

Views: 584

Answers (1)

BrantApps
BrantApps

Reputation: 6472

OK! I've got it working. I have added the following line to the library build gradle to forcibly add the generated "R" files onto the test classpath;

sourceSets {
  test.java.srcDirs += "build/generated/source/r/debug"
}

With this I have reached the nirvana of Robolectric tests with;

./gradlew core:lib:test

and Espresso 2.0-based integration with;

./gradlew connectedAndroidTest

Stop the clock for unit and integration test support in the IDE.... oh, what's that? 7 YEARS?! No love lost. Kudos to this answer that showed me how to forcibly add stuff to the test classpath.

Upvotes: 5

Related Questions