Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing a network response. Works when debugging, not when actually running

I am currently attempting to test that a network response is actually being received.

While I understand that this isn't what I should be doing with regards to testing, its a curiosity of my own volition and I'd like to carry on if possible.

As it stands, I have successfully created the test. A request is sent to a volley queue without issue.

Now the odd part:

That request is never executed. Here's an idea of how I'm testing it:

 @Test
    public void testSimpleGetResponseFromServerVolley() throws Exception {
        final CountDownLatch signal = new CountDownLatch(1);

        NetworkClass.NetworkListener listener = new NetworkClass.NetworkListener() {
            @Override
            public void onResponse(Response response) {
                assertThat(response != null);
                System.out.println("Got Response");
                signal.countDown();

            }

            @Override
            public void onError(Throwable error) {
                System.out.println("No Response");
                signal.countDown();
            }
        };
        NetworkClass.getResponseFromServer(null, listener);
        signal.await();
    }

This code unexpectedly causes the test to hang and never complete.

However this is where I stop losing comprehension of the situation:

If I run the test via debug and step through line by line, the test successfully executes, and response is received.

What I think is happening:

When I step through via debug, the volley requestQueue successfully carries on and makes the request, and the response is received before await() is called.

When I don't step through via debug, await() is blocking the thread which handles all of that.

Any ideas on how I can handle this?

like image 883
VicVu Avatar asked May 04 '16 15:05

VicVu


1 Answers

Volley relies on Looper.getMainLooper() to handle its executions. When using a RobolectricTestRunner, Robolectric mocks this out and as such it will not be correctly set up, thus resulting in a failed test.

In my specific case, when I was using breakpoints, the system actually does set up the main looper, because the system is utilizing it to show the breakpoints / debugging tools. This thus describes the reasoning behind the behaviour found in my initial question.

Now for a solution as to getting real network responses with Volley during a unit test, the executor must be changed to not be using the main looper.

As an easy solution, create a request queue that relies on Executor.singleThreadExecutor() instead of the Main Looper.

Here is what I mean:

    //Specific test queue that uses a singleThreadExecutor instead of the mainLooper for testing purposes.
public RequestQueue newVolleyRequestQueueForTest(final Context context) {
    File cacheDir = new File(context.getCacheDir(), "cache/volley");
    Network network = new BasicNetwork(new HurlStack());
    ResponseDelivery responseDelivery = new ExecutorDelivery(Executors.newSingleThreadExecutor());
    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network, 4, responseDelivery);
    queue.start();
    return queue;
}

Then, use that as your request queue for Volley during the tests.

The key here is:

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

Hope this helps!

like image 176
VicVu Avatar answered Oct 30 '22 03:10

VicVu