Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing with Android volley

I would like to know how can I create unit tests for the volley framework. Mock the requests, the responses so that I can create unit tests that wont require a webservice to be working and network accesss.

I've googled it but I don't find much information about the framework at all

like image 502
apinho Avatar asked Sep 04 '13 15:09

apinho


2 Answers

I implemented a subclass of HttpStack named FakeHttpStack that load fake response body from local file located in res/raw. I did this for development purpose, i.e., I can develop something for new API before server is ready, but you may learn something (e.g., overriding HttpStack#peformRequest and createEntity) from here.

/**  * Fake {@link HttpStack} that returns the fake content using resource file in res/raw.  */ class FakeHttpStack implements HttpStack {     private static final String DEFAULT_STRING_RESPONSE = "Hello";     private static final String DEFAULT_JSON_RESPONSE = " {\"a\":1,\"b\":2,\"c\":3}";     private static final String URL_PREFIX = "http://example.com/";     private static final String LOGGER_TAG = "STACK_OVER_FLOW";      private static final int SIMULATED_DELAY_MS = 500;     private final Context context;      FakeHttpStack(Context context) {         this.context = context;     }      @Override     public HttpResponse performRequest(Request<?> request, Map<String, String> stringStringMap)             throws IOException, AuthFailureError {         try {             Thread.sleep(SIMULATED_DELAY_MS);         } catch (InterruptedException e) {         }         HttpResponse response                 = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK"));         List<Header> headers = defaultHeaders();         response.setHeaders(headers.toArray(new Header[0]));         response.setLocale(Locale.JAPAN);         response.setEntity(createEntity(request));         return response;     }      private List<Header> defaultHeaders() {         DateFormat dateFormat = new SimpleDateFormat("EEE, dd mmm yyyy HH:mm:ss zzz");         return Lists.<Header>newArrayList(                 new BasicHeader("Date", dateFormat.format(new Date())),                 new BasicHeader("Server",                         /* Data below is header info of my server */                         "Apache/1.3.42 (Unix) mod_ssl/2.8.31 OpenSSL/0.9.8e")         );     }      /**      * returns the fake content using resource file in res/raw. fake_res_foo.txt is used for      * request to http://example.com/foo      */     private HttpEntity createEntity(Request request) throws UnsupportedEncodingException {         String resourceName = constructFakeResponseFileName(request);         int resourceId = context.getResources().getIdentifier(                 resourceName, "raw", context.getApplicationContext().getPackageName());         if (resourceId == 0) {             Log.w(LOGGER_TAG, "No fake file named " + resourceName                     + " found. default fake response should be used.");         } else {             InputStream stream = context.getResources().openRawResource(resourceId);             try {                 String string = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));                 return new StringEntity(string);             } catch (IOException e) {                 Log.e(LOGGER_TAG, "error reading " + resourceName, e);             }         }          // Return default value since no fake file exists for given URL.         if (request instanceof StringRequest) {             return new StringEntity(DEFAULT_STRING_RESPONSE);         }         return new StringEntity(DEFAULT_JSON_RESPONSE);     }      /**      * Map request URL to fake file name      */     private String constructFakeResponseFileName(Request request) {         String reqUrl = request.getUrl();         String apiName = reqUrl.substring(URL_PREFIX.length());         return "fake_res_" + apiName;     } } 

To use FakeHttpStack, you just have to pass it to your RequestQueue. I override RequestQueue too.

public class FakeRequestQueue extends RequestQueue {     public FakeRequestQueue(Context context) {         super(new NoCache(), new BasicNetwork(new FakeHttpStack(context)));     } } 

Good point for this approach is that, it doesn't require much change in your code. You just have to switch your RequestQueue to FakeRequestQueue when testing. Thus, it can be used in acceptance testing or system testing.

On the other hand, for unit testing, there might be more compact way. For instance, you can implement your Request.Listener subclass as separate class so that onResponse method can be easily tested. I recommend you to put more detail about what you want to test or put some code fragment.

like image 84
Kazuki Avatar answered Sep 20 '22 01:09

Kazuki


Take a look at volley tests folder, there you can find examples.

MockCache.java MockHttpClient.java MockHttpStack.java MockHttpURLConnection.java MockNetwork.java MockRequest.java MockResponseDelivery.java 
like image 26
Dmytro Danylyk Avatar answered Sep 22 '22 01:09

Dmytro Danylyk