Square retrofit server mock for testing Square retrofit server mock for testing android android

Square retrofit server mock for testing


Mock Retrofit 2.0 Requests for Testing

As the old mechanisms like creating MockClient class and implementing it from Client are not working anymore with Retrofit 2.0, here I describe a new way of doing that. All what you need to do now is to add your custom interceptors for OkHttpClient like it is shown below. FakeInterceptor class just overrides intercept method and in the case if application is in DEBUG mode return given JSON.

RestClient.java

public final class RestClient {    private static IRestService mRestService = null;    public static IRestService getClient() {        if(mRestService == null) {            final OkHttpClient client = new OkHttpClient();            // ***YOUR CUSTOM INTERCEPTOR GOES HERE***            client.interceptors().add(new FakeInterceptor());            final Retrofit retrofit = new Retrofit.Builder()                            // Using custom Jackson Converter to parse JSON                            // Add dependencies:                            // com.squareup.retrofit:converter-jackson:2.0.0-beta2                    .addConverterFactory(JacksonConverterFactory.create())                            // Endpoint                    .baseUrl(IRestService.ENDPOINT)                    .client(client)                    .build();            mRestService = retrofit.create(IRestService.class);        }        return mRestService;    }}

IRestService.java

public interface IRestService {    String ENDPOINT = "http://www.vavian.com/";    @GET("/")    Call<Teacher> getTeacherById(@Query("id") final String id);}

FakeInterceptor.java

public class FakeInterceptor implements Interceptor {     // FAKE RESPONSES.    private final static String TEACHER_ID_1 = "{\"id\":1,\"age\":28,\"name\":\"Victor Apoyan\"}";    private final static String TEACHER_ID_2 = "{\"id\":1,\"age\":16,\"name\":\"Tovmas Apoyan\"}";    @Override    public Response intercept(Chain chain) throws IOException {        Response response = null;        if(BuildConfig.DEBUG) {            String responseString;            // Get Request URI.            final URI uri = chain.request().url().uri();            // Get Query String.            final String query = uri.getQuery();            // Parse the Query String.            final String[] parsedQuery = query.split("=");            if(parsedQuery[0].equalsIgnoreCase("id") && parsedQuery[1].equalsIgnoreCase("1")) {                responseString = TEACHER_ID_1;            }            else if(parsedQuery[0].equalsIgnoreCase("id") && parsedQuery[1].equalsIgnoreCase("2")){                responseString = TEACHER_ID_2;            }            else {                responseString = "";            }            response = new Response.Builder()                    .code(200)                    .message(responseString)                    .request(chain.request())                    .protocol(Protocol.HTTP_1_0)                    .body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes()))                    .addHeader("content-type", "application/json")                    .build();        }        else {            response = chain.proceed(chain.request());        }        return response;    }}

Source code of project on GitHub


I decided to try method 1 as follows

public class MockClient implements Client {    @Override    public Response execute(Request request) throws IOException {        Uri uri = Uri.parse(request.getUrl());        Log.d("MOCK SERVER", "fetching uri: " + uri.toString());        String responseString = "";        if(uri.getPath().equals("/path/of/interest")) {            responseString = "JSON STRING HERE";        } else {            responseString = "OTHER JSON RESPONSE STRING";        }        return new Response(request.getUrl(), 200, "nothing", Collections.EMPTY_LIST, new TypedByteArray("application/json", responseString.getBytes()));    }}

And using it by:

RestAdapter.Builder builder = new RestAdapter.Builder();builder.setClient(new MockClient());

It works well and allows you to test your json strings without having to contact the real server!


Testing JSON deserialization to your objects (presumably with TypeAdapters?) seems like a separate problem that require separate unit tests.

I use version 2 personally. It affords type-safe, refactor-friendly code that can be easily debugged and altered. After all, what good is declaring your API as interfaces if you aren't creating alternate versions of them for testing! Polymorphism for the win.

Another option is using a Java Proxy. This is actually how Retrofit (currently) implements its underlying HTTP interaction. This will admittedly require more work, but would allow for much more dynamic mocks.