Getting Robolectric to work with Volley
Asked Answered
P

2

15

I am trying to get Volley working with Robolectric. I can see that my HTTP request is getting called, and parseNetworkResponse is getting called (I'm sending a custom subclass of JsonRequest), but my Listener is NOT getting called. Any advice? Here is a code sample:

@Test
public void testTypeAheadClient() throws Exception {
    Robolectric.getFakeHttpLayer().interceptHttpRequests(false);
    //mRemoteRequestQueue and mCustomRequest are set up previously
    mRemoteRequestQueue.add(mCustomRequest);
}

private static class CustomRequest extends JsonRequest<MyObject> {
    public CustomRequest(String url,
                         Response.Listener<MyObject> listener,
                         Response.ErrorListener errorListener) {
        super(Request.Method.GET, url, null, listener, errorListener);
    }

    @Override
    protected Response<MyObject> parseNetworkResponse(NetworkResponse response) {
        System.out.println("in parseNetworkResponse");
        try {
            MyObject myObject = new MyObject(new JSONArray(new String(response.data, "UTF-8")));
            return Response.success(myObject, HttpHeaderParser.parseCacheHeaders(response));
        } catch (Exception e) {
            e.printStackTrace();
            return Response.error(new ParseError(e));
        }
    }
}
Planchette answered 29/5, 2013 at 14:27 Comment(2)
As you're using callback I suppose that is an async library. To use Robolectric with Android Async Http lib you need to set your own thread pool. Maybe in this case the same solution can be adopted. groups.google.com/forum/#!msg/robolectric/Z3Yg04gL4hg/…Hamann
If you got this to work could you post your whole test code?Embosom
F
19

I solved that same problem by replacing the RequestQueue's ResponseDelivery with one that doesn't use the Looper.getMainLooper() but a new Executor. Example code:

public static RequestQueue newRequestQueueForTest(final Context context, final OkHttpClient okHttpClient) {
    final File cacheDir = new File(context.getCacheDir(), "volley");

    final Network network = new BasicNetwork(new OkHttpStack(okHttpClient));

    final ResponseDelivery responseDelivery = new ExecutorDelivery(Executors.newSingleThreadExecutor());

    final RequestQueue queue =
            new RequestQueue(
                    new DiskBasedCache(cacheDir),
                    network,
                    4,
                    responseDelivery);

    queue.start();

    return queue;
}

Note: use Robolectric-2.2-SNAPSHOT, the previous version doesn't play well with Volley.

Hope this helps

Fiddle answered 2/8, 2013 at 21:32 Comment(5)
this worked perfectly, in that it allowed the callbacks to execute... however, it now generates the dreaded "Stub!" exception on this line: at org.apache.http.ProtocolVersion.<init>(ProtocolVersion.java:5) which is called from: com.android.volley.toolbox.HurlStack.performRequest(HurlStack.java:108) at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:93) at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:105)Solenoid
If you get the ProtocolVersion stub exception it means that you need to move robolectric higher up in your build path/pom.xml.Dillydally
YES - this was just what I needed. So to wrap things up in a nice package you can setup a nice little volley class and start it like this volley = new Volley(RuntimeEnvironment.application, new ExecutorDelivery(Executors.newSingleThreadExecutor()));Philbert
What is "okHttpClient" suppose to be, can you give an example of how to use this?Granese
But with Volley?? ModelController.setupRequestQueueTesting(newRequestQueueForTest(new OkHttpClient()));Granese
K
0

Inspired by @Thomas Moerman's answer, I created this class:

public class RealRequestQueue {

    public static Builder newBuilder() {
        return new Builder();
    }

    public static final class Builder {
        private Cache mCache;
        private Network mNetwork;

        private Builder() {
        }

        public Builder cache(Cache val) {
            mCache = val;
            return this;
        }

        public Builder network(Network val) {
            mNetwork = val;
            return this;
        }

        public RequestQueue build() {
            if (mNetwork == null) mNetwork = new BasicNetwork(new HttpStack() {
                @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
                    return null;
                }
            });
            if (mCache == null) {
                Context context = RuntimeEnvironment.application.getApplicationContext();
                mCache = new DiskBasedCache(new File(context.getCacheDir(), "volley"));
            }

            ResponseDelivery responseDelivery = new ExecutorDelivery(Executors.newSingleThreadExecutor());
            final RequestQueue queue = new RequestQueue(mCache, mNetwork, 4, responseDelivery);

            return queue;
        }
    }
}

I then spy on the request queue and inject it in to the system under test

mQueue = spy(RealRequestQueue.newBuilder().network(mNetwork).build());
Kangaroo answered 29/4, 2016 at 9:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.