Categories
android

Mocking API Responses using a Retrofit Client in Android (Retrofit 1.9)

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("\n");
        }
        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

 

 

6 replies on “Mocking API Responses using a Retrofit Client in Android (Retrofit 1.9)”

Nice formatted and properly coded snippets, I enjoy this article, but two things.
Even if it’s an article i’d like to point out not spreading the usage of empty
catch (UnauthorizedException unauthorised), we have enough of that already 🙂

Next thing, is just a minor thing, which is following through on your creating attributes for configuration strings(e.a: http://api.theysaidso.com/), along with actually making consts out of them, since they are not changing.

Now I can appreciate all these things being done just to keep the clutter down in your examples, but once you post something, people might end up using them, which makes you someone that should set an example. All in all, thanks for writing this 🙂

Hi Rebecca, Really nice tutorial. I’m new to android and i’m having a hard time teaching myself android. I have tried looking to materials but they don’t seem to answer my questions. I was wondering if you could post a tutorial of how to read a json response (Both success and error) from an api and display it on the interface.

this is the success response
{

“error”: false,

“status”: 200,

“data”: {

“id”: 1,

“name”: “nimzy”,

“email”: “nimzy@pass.com”,

“phone”: “254724844946”,

“apikey”: “0lxVzVyIXgWSsdsKJNJmfdvnaXsKD5hanf9u”

}

}

this is the error response

{

“error”: true,

“message”: “Unauthorized Access!”,

“status”: 401

}

thanks in advance

Comments are closed.