Writing test cases in Android can be quite a daunting task, especially the handling of different server responses. Testing error responses can be quite problematic and your app might not cover all the different scenarios.

If you are using Retrofit 1.9 and below to do your network calls, testing error responses can be quite simple. There are a couple of ways to test Retrofit calls. In this post we will look at making the Client return different responses which are stored in .JSON files within the test project.

Firstly, create a RetrofitMockClient within your test project that will replace your response with the custom responses that you define.

public class RetrofitMockClient implements Client { private String jsonResponse; private int statusCode = 200; private String reason; private static final String MIME_TYPE = "application/json"; public RetrofitMockClient(int statusCode, String reason, String jsonResponse) { this.statusCode = statusCode; this.reason = reason; this.jsonResponse = jsonResponse; } @Override public Response execute(Request request) throws IOException { return createDummyJsonResponse(request.getUrl(), statusCode, reason, jsonResponse); } private Response createDummyJsonResponse(String url, int responseCode, String reason, String json) { return new Response(url, responseCode, reason, Collections.EMPTY_LIST, new TypedByteArray(MIME_TYPE, json.getBytes())); } }

public class RestServiceMockUtils { public static String convertStreamToString(InputStream is) throws Exception { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { sb.append(line).append("

"); } reader.close(); return sb.toString(); } public static String getStringFromFile(Context context, String filePath) throws Exception { final InputStream stream = context.getResources().getAssets().open(filePath); String ret = convertStreamToString(stream); //Make sure you close all streams. stream.close(); return ret; } public static RetrofitMockClient getClient(Context context, final int httpStatusCode, String reason, String responseFileName) throws Exception { return new RetrofitMockClient(httpStatusCode, reason, getStringFromFile(context, responseFileName)); } }

Create the response JSON for the service you wish to test. In this example, we will be testing a service that returns random quotes for a logged in user. The API call can have HTTP status codes such as 401 Unauthorised, 200 OK, 500 Internal Server Error etc.

For example, a 401 Unauthorised Response could look like this: quote_401_unauthorised.json

{ "error": { "code": 401, "message": "Unauthorized" } }

These JSON files should be created and saved in the /androidTest/assets folder.

Then create a test in the androidTest folder:

public class QuoteOfTheDayServiceTests extends InstrumentationTestCase { public static final String TAG = "QODServiceTest"; public static final String BASE_API_URL = "http://api.theysaidso.com/"; @SmallTest public void testAuthoriseFailsForIncorrectSessionId() throws Exception { String jsonResponseFileName = "quote_401_unauthorised.json"; int expectedHttpResponse = 401; String reason = "Unauthorised"; //Create RetrofitMockClient with the expected JSON response and code. RetrofitMockClient retrofitMockClient = RestServiceMockUtils.getClient(getInstrumentation().getContext(), expectedHttpResponse, reason, jsonResponseFileName); RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint(BASE_API_URL) .setClient(retrofitMockClient) .setConverter(new JacksonConverter()) .setErrorHandler(new RetrofitErrorHandler()) .build(); RestService restServiceClient = restAdapter.create(RestService.class); //Run test code - you can test anything you want to here, test the correct response, the way the UI displays for certain mock JSON. String incorrectApiKey = "incorrectApiKey"; try { String quote = restServiceClient.getQuoteOfTheDay(incorrectApiKey); Assert.fail("Should have thrown unauthorised exception"); } catch (UnauthorizedException unauthorised) { Log.d(TAG, "Successfully caught unauthorised exception when incorrect API key was passed"); } } }

There you have it, your custom Retrofit Client will now return the JSON that you have specified. Yay!

Pros of testing this way:

Simple & easy to understand.

Possible JSON response is stored within the test project – new developers will easily understand what the services are doing and what the expected server responses look like.

Easy way to test different response codes and how your app reacts to them.

It is also possible to test different returned headers with this mechanism.

No need to run a mocking web server.

Cons of testing this way:

Hard to test complex server responses (i.e. dates that should change dynamically based on current date).

Limited to the JSON that you define.

Hard to emulate network speed.

In the next post, we will look at using other mechanisms, like Mockito, for testing our APIs.

Code on Github