Simulate a bad network with retrofit 2 (according to the actual, i.e. not ridiculed, API)

In Retrofit 1.x, I used the following template to create api service classes that simulated a bad network connection for certain build options.

// Retrofit 1 private <T> T create(Class<T> apiServiceClass) { T apiService = restAdapter.create(apiServiceClass); if (!BuildConfig.IS_PRODUCTION_BUILD) { endpoints = mockRestAdapter.create(apiServiceClass, apiService); } return apiService; } 

The nice thing is that my actual API endpoints are used. This way, I can see how the application behaves on a broken connection, and I do not need to give false / artificial answers.

Now in the Retrofit 2 API for the MockRestAdapter or rather, the MockRetrofit completely changed. MockRetrofit#create now returns a BehaviorDelegate . If I try to use the same template as before,

 // Retrofit 2 private <T> T create(Class<T> apiServiceClass) { T apiService = retrofit.create(apiServiceClass); if (!BuildConfig.IS_PRODUCTION_BUILD) { endpoints = mockRetrofit.create(apiServiceClass).returning(???); } return apiService; } 

I am stuck on returning(???) . returning expects an implementation of Call<?> . But I can’t figure out how to implement it so that it works, like my Retrofit 1 example (maybe it is not intended).

So my question is: in general, how can I achieve the aforementioned Retrofit 1 pattern for modeling a bad network in a real API using Retrofit 2?

+6
source share
1 answer

I finally figured it out. The idea is to use OkHttp application interceptors. Here is the solution.

First create a NetworkBehavior .

 final NetworkBehavior behavior = NetworkBehavior.create(); behavior.setDelay(2000, TimeUnit.MILLISECONDS); behavior.setFailurePercent(50); behavior.setVariancePercent(50); 

Of course, you can provide behavior the user interface component to dynamically change these values.

When configuring OkHttpClient add the following interceptor.

 final OkHttpClient.Builder builder = new OkHttpClient.Builder(); if (!BuildConfig.IS_PRODUCTION_BUILD) { builder.addInterceptor(new HttpLoggingInterceptor()); builder.addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { try { Thread.sleep(behavior.calculateDelay(TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { e.printStackTrace(); } if (behavior.calculateIsFailure()) { return new Response.Builder() .code(500) .message("MockError") .protocol(Protocol.HTTP_1_1) .request(chain.request()) .body(ResponseBody.create(MediaType.parse("text/plain"), "MockError")) .build(); } return chain.proceed(chain.request()); } }); } 

Note that you must add a logging interceptor before sending request logs. Of course, a manually created response object can be adapted to your taste. Some values ​​are required (e.g. protocol or request ). If you do not specify them, you will receive NPE. The same approach will indeed work for Retrofit 1.

+7
source

All Articles