简体   繁体   中英

Getting ClassNotFoundException when running Robolectric tests with the Maven surefire plugin

I've set up a project in Eclipse using the Android Maven integration, and Robolectric for some tests.

The tests run fine when I deploy them in Eclipse. However, when I try to build the project with the Maven "install" goal (this is actually a library that I need in my local Maven repository), it fails on these same tests.

Logs show the following error:

testAll((package).MyTest)  Time elapsed: 0.006 sec  <<< ERROR!
java.lang.RuntimeException: java.lang.ClassNotFoundException: caught an exception while obtaining a class file for (package).R
    at com.xtremelabs.robolectric.RobolectricTestRunner.createResourceLoader(RobolectricTestRunner.java:316)
    at com.xtremelabs.robolectric.RobolectricTestRunner.setupApplicationState(RobolectricTestRunner.java:270)
    at com.xtremelabs.robolectric.RobolectricTestRunner.internalBeforeTest(RobolectricTestRunner.java:221)
    at com.xtremelabs.robolectric.RobolectricTestRunner.methodBlock(RobolectricTestRunner.java:201)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:59)
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:120)
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:103)
    at org.apache.maven.surefire.Surefire.run(Surefire.java:169)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:350)
    at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1021)
Caused by: java.lang.ClassNotFoundException: caught an exception while obtaining a class file for (package).R
    at javassist.Loader.findClass(Loader.java:359)
    at com.xtremelabs.robolectric.bytecode.RobolectricClassLoader.findClass(RobolectricClassLoader.java:60)
    at javassist.Loader.loadClass(Loader.java:311)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
    at com.xtremelabs.robolectric.bytecode.RobolectricClassLoader.loadClass(RobolectricClassLoader.java:37)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:169)
    at com.xtremelabs.robolectric.RobolectricTestRunner.createResourceLoader(RobolectricTestRunner.java:312)
    ... 22 more
Caused by: com.xtremelabs.robolectric.bytecode.IgnorableClassNotFoundException: msg because of javassist.NotFoundException: (package).R
    at com.xtremelabs.robolectric.bytecode.AndroidTranslator.onLoad(AndroidTranslator.java:80)
    at javassist.Loader.findClass(Loader.java:340)
    ... 29 more

where (package) is of course the name of my main package. Here's the relevant section of my POM:

  <dependencies>
    <dependency>
      <groupId>com.google.android</groupId>
      <artifactId>android</artifactId>
      <version>2.1.2</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>com.pivotallabs</groupId>
        <artifactId>robolectric</artifactId>
        <version>0.9.8</version>
        <type>jar</type>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.hamcrest</groupId>
        <artifactId>hamcrest-core</artifactId>
        <version>1.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
        <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
   <defaultGoal>package</defaultGoal>
    <plugins>
      <plugin>
        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
        <artifactId>maven-android-plugin</artifactId>
        <version>2.8.3</version>
        <configuration>
        <genDirectory>${project.basedir}/gen</genDirectory>
          <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
          <assetsDirectory>${project.basedir}/assets</assetsDirectory>
          <resourceDirectory>${project.basedir}/res</resourceDirectory>
          <nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>
          <sdk>
            <platform>7</platform>
          </sdk>
          <deleteConflictingFiles>true</deleteConflictingFiles>
          <undeployBeforeDeploy>true</undeployBeforeDeploy>
        </configuration>
        <extensions>true</extensions>
      </plugin>

      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.6</version>
        <configuration>
            <excludes>
                <exclude>**/Test*.java</exclude>
            </excludes>
        </configuration>
    </plugin>      
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
        <version>2.8</version>
    </plugin>
    </plugins>
  </build>

As you can see, I've tried adding the "genDirectory" option to the Maven Android plugin. But to no avail.

What am I missing to make the surefire plugin "see" the R class?

One more thing: the R class is not actually referenced by my code.

I also got exactly this issue.

So I compared carefully between RobolectricSample project and my project.

To my surprise, the RobolectricSample project also could NOT work if I didn't run the command line of "mvn clean test" first.

Therefore I analysed the difference and found that the command line compiled the "gen/xxx/R.java" to "target/classes/xxx/R" too.

That's the trick of success so I did the following steps: 1. right click project -> Java Build; 2. change the "{project}/gen" output folder as "target/class" (instead of original "target/android-classes")

That's it and hope this helps.

I found that the only way to fix this issue was to place a fake R.java file into the package:

    public class R {
        public static final class attr {
        }

        public static final class drawable {
        }

        public static final class id {
        }

        public static final class layout {
        }

        public static final class string {
        }
    }

This should only be necessary under the following circumstances:

  1. Maven library project
  2. unit test dependencies on Robolectric
  3. R.java not being generated or not found on maven classpath.

Note: You can put R.java in your test sources so that it isn't deployed. This won't then interfere with actual resources created.

I've had the same problem when trying to run a test from Eclipse, first time after adding Robolectric.

What solved the problem for me was mvn clean test on the command line. After that, the test ran OK from Eclipse as well.

And make sure you have <packaging>apk</packaging> in your pom.xml.

I had this same issue when running Robolectric tests both in eclipse and on the command line via mvn clean test . Ie a java.lang.ClassNotFoundException complaining that my R.class file was not found. Indeed, there was no R.class file since my project is an Android library that has no resources.

A dirty hack to get rid of the error is to create a <project-home>/res/values/strings.xml file with a single unused string. Then the R.java and the corresponding R.class are generated and the error goes away.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM