Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NullPointerException on reflection during Robolectric startup - any hints?

I am developing an Android project on Eclipse, and I'm trying to switch from running tests on the emulator/device (which is very slow) to Robolectric.

I replaced the Android libs with Robolectric's, added JUnit to the path, changed the test case back to a regular TestCase and added the suggested @RunWith(RobolectricTestRunner.class) from the Quick Start guide (making the needed changes to instantiate my Activity instead of relying on Android's activity testing to do it for me).

However, when I run the test, I get:

java.lang.NullPointerException
 at com.xtremelabs.robolectric.RobolectricTestRunner.isInstrumented(RobolectricTestRunner.java:123)
 at com.xtremelabs.robolectric.RobolectricTestRunner.<init>(RobolectricTestRunner.java:72)
 at com.xtremelabs.robolectric.RobolectricTestRunner.<init>(RobolectricTestRunner.java:57)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
 at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:31)
 at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:24)
 at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
 at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)
 at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
 at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:24)
 at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.<init>(JUnit4TestReference.java:29)
 at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.<init>(JUnit4TestClassReference.java:25)
 at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:40)
 at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:30)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

This seems to be related to this code (from 0.9 tag, since 0.9.1 tag doesn't have it) in RobolectricTestRunner.java:

private static boolean isInstrumented() {
    return RobolectricTestRunner.class.getClassLoader().getClass().getName().contains(RobolectricClassLoader.class.getName());
}

but I can't understand how, since this reflection should work from the class itself.

Also, I could swear that it ran once before failing repeatedly - I've deleted the robolectric cache (as suggested here) and replaced Eclipse's JUnit with the latest (4.8.2), but nothing changed.

Any hints?

UPDATE: I tried to create a new, Java (i.e., plain, non-Android) test project, just as described on the quick start guide. However, now the test run complains about not having AndroidManifest.xml:

java.lang.RuntimeException: java.io.FileNotFoundException: /Users/chester/Documents/workspace/minitruco-android/minitruco-android-robolectric-test/AndroidManifest.xml (No such file or directory)
    at com.xtremelabs.robolectric.RobolectricTestRunner.createResourceLoader(RobolectricTestRunner.java:245)
    at com.xtremelabs.robolectric.RobolectricTestRunner.setupApplicationState(RobolectricTestRunner.java:215)
    at com.xtremelabs.robolectric.RobolectricTestRunner.internalBeforeTest(RobolectricTestRunner.java:163)
    at com.xtremelabs.robolectric.RobolectricTestRunner.methodBlock(RobolectricTestRunner.java:143)
    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.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.io.FileNotFoundException: /Users/chester/Documents/workspace/minitruco-android/minitruco-android-robolectric-test/AndroidManifest.xml (No such file or directory)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:137)
    at java.io.FileInputStream.<init>(FileInputStream.java:96)
    at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:87)
    at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:178)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(Unknown Source)
    at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
    at com.xtremelabs.robolectric.RobolectricTestRunner.findResourcePackageName(RobolectricTestRunner.java:255)
    at com.xtremelabs.robolectric.RobolectricTestRunner.createResourceLoader(RobolectricTestRunner.java:236)
    ... 18 more

I guess the test should load the files from the original project (minitruco-android), which shows up in both the test project's build path and on the Run/Debug build configuration on Eclipse (under the test project's classpath entry). Anyway, I've copied the file from my original test project (just for the sake of testing), but then it complains about R.java (and that should really have been imported from the original project):

java.lang.RuntimeException: java.lang.ClassNotFoundException: caught an exception while obtaining a class file for me.chester.minitruco.test.R
    at com.xtremelabs.robolectric.RobolectricTestRunner.createResourceLoader(RobolectricTestRunner.java:245)
    at com.xtremelabs.robolectric.RobolectricTestRunner.setupApplicationState(RobolectricTestRunner.java:215)
    at com.xtremelabs.robolectric.RobolectricTestRunner.internalBeforeTest(RobolectricTestRunner.java:163)
    at com.xtremelabs.robolectric.RobolectricTestRunner.methodBlock(RobolectricTestRunner.java:143)
    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.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.ClassNotFoundException: caught an exception while obtaining a class file for me.chester.minitruco.test.R
    at javassist.Loader.findClass(Loader.java:359)
    at com.xtremelabs.robolectric.RobolectricClassLoader.findClass(RobolectricClassLoader.java:60)
    at javassist.Loader.loadClass(Loader.java:311)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
    at com.xtremelabs.robolectric.RobolectricClassLoader.loadClass(RobolectricClassLoader.java:37)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:336)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:186)
    at com.xtremelabs.robolectric.RobolectricTestRunner.createResourceLoader(RobolectricTestRunner.java:237)
    ... 18 more
Caused by: javassist.NotFoundException: me.chester.minitruco.test.R
    at javassist.ClassPool.get(ClassPool.java:436)
    at com.xtremelabs.robolectric.AndroidTranslator.onLoad(AndroidTranslator.java:68)
    at javassist.Loader.findClass(Loader.java:340)
    ... 26 more

The only different thing between my setup and the quick start is that I'm keeping test sources on the test project and regular sources on the regular project (since the first builds, I'd assume the test project sees the regular sources - which, of course, it depends heavily upon).

I'm using SoyLatte, but tried also Mac OS's default 1.6 JVM, with the same results.

Thank you.

like image 764
chesterbr Avatar asked Nov 21 '10 05:11

chesterbr


3 Answers

We have had the same problems in the past. What works for us is extending RoboletricTestRunner and providing it a RoboletricConfig instance that is aware of our Project's location. This way I don't have to tinker with any run configurations with eclipse, it just works.

    package ...;

    import java.io.File;

    import org.junit.runners.model.InitializationError;

    import com.xtremelabs.robolectric.RobolectricConfig;
    import com.xtremelabs.robolectric.RobolectricTestRunner;

    public class TestRunner extends RobolectricTestRunner {

        public static final string MAIN_PROJECT_PATH = "../path_to_android_project";

        public TestRunner(Class<?> testClass) throws InitializationError {
             super(testClass, new RobolectricConfig(new File(MAIN_PROJECT_PATH)));
        }
    }
like image 154
Michael Avatar answered Nov 16 '22 08:11

Michael


Normally you won't need to extend TestCase, but I don't think that should be causing this problem. Could you include the source of the failing test?

Regarding the simplified project in your update, make sure that Eclipse is configured to set the current working directory to the root of the main project, not the test project, so it will find AndroidManifest.xml and the res directory.

like image 33
Xian Avatar answered Nov 16 '22 06:11

Xian


No need to create a custom RoboelectricTestRunner, just play a bit with your 'Run Configurations' on Eclipse. On the configuration for running your tests, go to the classpath tab and ensure that the libraries required for your test, e.g. robolectric-2.2-jar-with-dependencies.jar and android.jar and the project itself are in the User Entries and ONLY the Java SDK is in the Bootstrap Entries.

Then add this file:

[project_path]/test/org.robolectric.Config.properties

 manifest=../AndroidManifest.xml
like image 2
Alécio Carvalho Avatar answered Nov 16 '22 06:11

Alécio Carvalho