robolectric

How to use Robolectric and still make real HTTP requests

Recently, I have been writing some unit tests for my application using Robolectric. The framework and plugin has allowed me to write some plain unit tests using Mockito which is great, however, today I came across a feature that I didn’t want to take advantage of.

I was testing a class that is responsible for making REST HTTP requests to a server and for this test I wanted to get real responses. However, when running the tests in Android Studio everything was fine, but as soon as I ran it from the command line using gradle I got the following error.


java.lang.RuntimeException: Unexpected call to execute, no pending responses are available. See Robolectric.addPendingResponse(). Request was: GET http://127.0.0.1/rest/543e7ee26c3f52cce18c365f
	at org.robolectric.tester.org.apache.http.FakeHttpLayer.emulateRequest(FakeHttpLayer.java:127)
	at org.robolectric.shadows.ShadowDefaultRequestDirector.execute(ShadowDefaultRequestDirector.java:162)
	at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java)
	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
	at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:83)
	at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:46)
	at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:63)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:476)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439)
	at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:259)
	at com.lsc.spear.services.REST.tasks.GetAssetByIdRequest.doInBackground(GetAssetByIdRequest.java:70...

This was down to a feature in Robolectric that allows developers to test their code without making real HTTP requests. See their blog article on this here

However, in my situation I wanted to make the real requests. You can turn this feature off using the method call.

Robolectric.getFakeHttpLayer().interceptHttpRequests(false);

I put it in my @Before annotated method so it was configured for all my tests.

Conflict with Robolectric and SlideUpPanelLayout

The other day I was trying to integrate Robolectric with my project that uses the SlideUpPanelLayout. If I removed either Robolectric from the test build or SlideUpPanelLayout from my project it fixed the issue (temporarily, because I needed both) When using Robolectric and SlideUpPanelLayout together I get the following error.

Test failed to run to completion. Reason: ‘Instrumentation run failed due to 'java.lang.IllegalAccessError''. Check device logcat for details
Test running failed: Instrumentation run failed due to 'java.lang.IllegalAccessError'

This error is down to a Gradle configuration error. The reason is that there are dependencies declared multiple times in the build and one of them needs to be excluded. The challenge in this situation is knowing which dependency it is.

To work this out look at the exception which in this case ended with

Caused by: java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
at com.sothree.slidinguppanel.ViewDragHelper.<init>(ViewDragHelper.java:392)
at com.sothree.slidinguppanel.ViewDragHelper.create(ViewDragHelper.java:348)
at com.sothree.slidinguppanel.ViewDragHelper.create(ViewDragHelper.java:361)
at com.sothree.slidinguppanel.SlidingUpPanelLayout.<init>(SlidingUpPanelLayout.java:334)
at com.sothree.slidinguppanel.SlidingUpPanelLayout.<init>(SlidingUpPanelLayout.java:263)
... 26 more

ViewDragHelper was the culprit so if in your IDE (Android Studio) open the search for class name (Command-O in OS X) and enter ViewDragHelper. You will see that there are multiple Jars that are returned. You will need to exclude the one that you don’t want.

In this situation we had the android-19 sdk, support-v4-19 and support-v4-20 and library-2.0.1 (the slideuppanellayout library) to solve this I needed to exclude support-v4.

So in the build gradle file for the project where I included robolectric I needed to add the following to the list of excludes.

exclude module: 'support-v4'

This solved the problem!

NullPointerException when using Robolectric and Google Play Services

Today whilst writing a unit test for my Android application I had issues using Robolectric in my application. After a lot of hunting around and narrowing down the problem I found that it is was because of the declaration of Google Play Services in my AndroidManifest.xml file.

The error I got was

java.lang.RuntimeException: java.lang.NullPointerException
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:240)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:177)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:105)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:355)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at org.robolectric.AndroidManifest$MetaData.init(AndroidManifest.java:698)
at org.robolectric.AndroidManifest.initMetaData(AndroidManifest.java:364)
at org.robolectric.res.builder.RobolectricPackageManager.addManifest(RobolectricPackageManager.java:364)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:77)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:430)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:236)
... 35 more

The key parts of this stack trace being the NullPointerException and the fact it was coming from AndroidManifest.java. The cause of this issue was down to the fact in the AndroidManifest.xml I have this declaration to include Google Maps.


<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />

The part that is causing issues is the @integer/google_play_services_version and it is something to do with the fact the google_play_services_version is embedded in the Jar and it cannot be processed at the point it needs to be.

How to fix this?
To fix this issue you will can hard code it but that is a very hacky solution. It would be better to define this value locally but still point it at the correct value, for some reason this works.

So, in the values section of your project create a new resource file and call it something like values.xml.

In that file add the following code


<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="gms_version">@integer/google_play_services_version</integer>
</resources>

Then in your AndroidManifest.xml file where @integer/google_play_services_version was previously declared then put @integer/gms_version

This will work around the issue which is open here.