An easy way to mock an API response using Retrofit, OkHttp, and Interceptor

Photo by Alvaro Reyes on Unsplash

Many times, Android developers need to start implementing features even when the backend is not ready yet. An easier way is to ask the backend developer to create the API service and just send fake content for the sake of it. The underlying notion is that we are not backend developers and it is not our responsibility to provide the endpoint.

Do you even Agile, Bro? What about User Stories and Acceptance Criteria?

I know what you are thinking and you are not wrong. But here’s the thing: Many times there are situations when it is not possible to go by the book. For example, it can happen that cross-platform teams start working together. The best you can do is to come together with backend developer and agree on the JSON response so no one is blocked by anyone.

Ok, this is sorted out but how Android developers can test their feature implementation against backend response without API being live?

There are a couple of options:

These are all good options but we wanted a convenient and easy solution to this problem. We didn’t want to spend time on “building” anything.

They say ‘fake it till you make it’. In this article, we’ll explore the option which involves using Interceptors offered by OkHttp to mock an API response. It’ll allow you to test your Retrofit REST service interface without changing anything on the code.

This article won’t explain how to use Retrofit or OkHttp as this is something which is out of the scope but you can easily find some very good tutorials on this topic like this.


Interceptors were introduced in okhttp2.2 and meant to be hooked with your HTTP calls so that you can intercept all outgoing requests and the incoming responses. They basically look like this:

public interface Interceptor { 
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
@Nullable Connection connection();
}
}
Observes, modifies, and potentially short-circuits requests going out and the corresponding responses coming back in. Typically interceptors add, remove, or transform headers on the request or response.

Interceptors from OkHttp are bad-ass and more powerful than you can think. They can be used in many different ways starting from logging to monitor the network calls our app makes and handling nasty situations. It allows you to rewrite requests to compress them or sign them or even transform the response body to workaround server problems.

In order to find a solution to our problem, we are prepared to deal with the consequences of rewriting response body because we are making a conscious call.

If you are also using Dagger2 like most of us, code for basic setup of OkHttpClient and Retrofit will look like this:

@Provides
@Singleton
@Named("OkHttpClient")
fun provideOkHttpClient(): OkHttpClient = OkHttpClient
.Builder()
.build()
@Provides
@Singleton
@Named("Retrofit")
fun provideRetrofit(@Named("OkHttpClient") client: OkHttpClient,
gson: Gson): Retrofit = Retrofit
.Builder()
.client(client)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()

This is how a very simple version of MockInterceptor looks like. We are using an example from Github API to make a point. It is better to have mocked JSON responses in a separate file for better organization and readability.

The key component in the code above is to check how Response object is created to execute emulation of backend response.

Next subsequent step is to register a network interceptor by calling addInterceptor() on OkHttpClient.Builder:

@Provides
@Singleton
@Named("OkHttpClient")
fun provideOkHttpClient(
@Named("MockInterceptor") authInterceptor: Interceptor): OkHttpClient = OkHttpClient
.Builder()
.addInterceptor(authInterceptor)
.build()
@Provides
@Singleton
@Named("MockInterceptor")
fun provideMockInterceptor(): Interceptor = MockInterceptor()

Again, this is only meant for testing in DEBUG mode and very likely there’ll be a proper AuthInterceptor for production code. You can then switch between the two when needed. This is also the reason why we have a check inside MockInterceptor to inform the user in case of a mistake.

//just to be on safe side
throw IllegalAccessError("MockInterceptor is only meant for Testing Purposes and bound to be used only with DEBUG mode")

One more thing

Imagine, if you want to see how your app reacts against different HTTP Status Codes and if it shows the expected UI element. On line 18 of the gist snippet above, we specified.code(SUCCESS_CODE)while creating the Responseobject in order to return the desired response. This could be a very useful feature because you can now mock HTTP Status Code by passing on the desired code in this function.