Square modified server mock for testing

What is the best way to mock a server for testing using a square frame structure .

Potential ways:

  • Create a new client modification and set it to RestAdapter.Builder (). setClient (). This includes parsing the Request object and returning json as the Response object.

  • Deploy this annotated interface as a mock class and use this instead of the version provided by RestAdapter.create () (do not test gson serialization)

Ideally, I want the moker server to provide json responses so that I can test gson serialization at the same time.

Any examples are welcome.

+88
android retrofit testing mocking mockwebserver
Jul 09 '13 at 9:29
source share
11 answers

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:

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

It works well and allows you to test your json strings without having to communicate with a real server!

+79
Jul 11 '13 at
source share

Mock Retrofit 2.0 Test Requests

Since old mechanisms, such as creating the MockClient class and implementing it from Client , no longer work with Retrofit 2.0, here I describe a new way to do this. All you have to do now is add your custom interceptors for OkHttpClient as shown below . The FakeInterceptor class simply overrides the intercept method and, if the application is in DEBUG mode, returns 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; } } 

GitHub project source code

+95
Dec 19 '15 at 21:06
source share

Testing JSON deserialization for your objects (presumably with TypeAdapters ?) Seems to be a separate issue requiring separate unit tests.

I use version 2 personally. It provides code that is safe to use with text, which is easily debugged and modified. In the end, what good is your API declaring as interfaces if you are not creating alternative versions for testing! Polymorphism for victory.

Another option is to use Java Proxy . This is actually how Retrofit (currently) implements its basic HTTP interaction. This admittedly will require more work, but will allow much more dynamic layouts.

+19
Oct. 15 '13 at 4:29
source share

You can also use something like Webservermock from Squareup! → https://github.com/square/okhttp/tree/master/mockwebserver

+9
Mar 10 '14 at 13:43
source share

I am a big fan of Apiary.io for taunting the API before moving to a real server.

You can also use flat .json files and read them from the file system.

You can also use a public API such as Twitter, Flickr, etc.

Here are some other helpful resources about Retrofit.

Slides: https://docs.google.com/presentation/d/12Eb8OPI0PDisCjWne9-0qlXvp_-R4HmqVCjigOIgwfY/edit#slide=id.p

Video: http://www.youtube.com/watch?v=UtM06W51pPw&feature=g-user-u

Project example: https://github.com/dustin-graham/ucad_twitter_retrofit_sample

+8
Aug 28 '13 at 0:51
source share

Mockery (disclaimer: Im author) was designed specifically for this purpose.

Mockery is a mock / test library focused on checking network layers with built-in Retrofit support. It automatically generates JUnit tests based on the specifications of this Api. The idea is to not write any tests manually; nor the introduction of interfaces for bullying server responses.

+7
Jul 13 '16 at 8:56
source share
  • First create your Retrofit interface.

     public interface LifeKitServerService { /** * query event list from server,convert Retrofit Call to RxJava Observerable * * @return Observable<HttpResult<List<Event>>> event list from server,and it has been convert to Obseverable */ @GET("api/event") Observable<HttpResult<List<Event>>> getEventList(); } 
  • Your requestor:

     public final class HomeDataRequester { public static final String TAG = HomeDataRequester.class.getSimpleName(); public static final String SERVER_ADDRESS = BuildConfig.DATA_SERVER_ADDR + "/"; private LifeKitServerService mServerService; private HomeDataRequester() { OkHttpClient okHttpClient = new OkHttpClient.Builder() //using okhttp3 interceptor fake response. .addInterceptor(new MockHomeDataInterceptor()) .build(); Retrofit retrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl(SERVER_ADDRESS) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create(new Gson())) .build(); //using okhttp3 inteception to fake response. mServerService = retrofit.create(LifeKitServerService.class); //Second choice,use MockRetrofit to fake data. //NetworkBehavior behavior = NetworkBehavior.create(); //MockRetrofit mockRetrofit = new MockRetrofit.Builder(retrofit) // .networkBehavior(behavior) // .build(); //mServerService = new MockLifeKitServerService( // mockRetrofit.create(LifeKitServerService.class)); } public static HomeDataRequester getInstance() { return InstanceHolder.sInstance; } public void getEventList(Subscriber<HttpResult<List<Event>>> subscriber) { mServerService.getEventList() .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber); } } 
  • If you use the second option (use the Retrofit interface for the Mock server data), you need MockRetrofit, use the following code:

     public final class MockLifeKitServerService implements LifeKitServerService { public static final String TAG = MockLifeKitServerService.class.getSimpleName(); private BehaviorDelegate<LifeKitServerService> mDelegate; private Gson mGson = new Gson(); public MockLifeKitServerService(BehaviorDelegate<LifeKitServerService> delegate) { mDelegate = delegate; } @Override public Observable<HttpResult<List<Event>>> getEventList() { List<Event> eventList = MockDataGenerator.generateEventList(); HttpResult<List<Event>> httpResult = new HttpResult<>(); httpResult.setCode(200); httpResult.setData(eventList); LogUtil.json(TAG, mGson.toJson(httpResult)); String text = MockDataGenerator.getMockDataFromJsonFile("server/EventList.json"); if (TextUtils.isEmpty(text)) { text = mGson.toJson(httpResult); } LogUtil.d(TAG, "Text:\n" + text); text = mGson.toJson(httpResult); return mDelegate.returningResponse(text).getEventList(); } 

4. My data is from the asset file (Asset / server / EventList.json), this file contains:

  { "code": 200, "data": [ { "uuid": "e4beb3c8-3468-11e6-a07d-005056a05722", "title": "title", "image": "http://image.jpg", "goal": 1500000, "current": 51233, "hot": true, "completed": false, "createdAt": "2016-06-15T04:00:00.000Z" } ] } 

5. If you use the okhttp3 interceptor, you need a self-tuning interceptor, for example:

 public final class MockHomeDataInterceptor implements Interceptor { public static final String TAG = MockHomeDataInterceptor.class.getSimpleName(); @Override public Response intercept(Chain chain) throws IOException { Response response = null; String path = chain.request().url().uri().getPath(); LogUtil.d(TAG, "intercept: path=" + path); response = interceptRequestWhenDebug(chain, path); if (null == response) { LogUtil.i(TAG, "intercept: null == response"); response = chain.proceed(chain.request()); } return response; } private Response interceptRequestWhenDebug(Chain chain, String path) { Response response = null; if (BuildConfig.DEBUG) { Request request = chain.request(); if (path.equalsIgnoreCase("/api/event")) { //get event list response = getMockEventListResponse(request); } } private Response getMockEventListResponse(Request request) { Response response; String data = MockDataGenerator.getMockDataFromJsonFile("server/EventList.json"); response = getHttpSuccessResponse(request, data); return response; } private Response getHttpSuccessResponse(Request request, String dataJson) { Response response; if (TextUtils.isEmpty(dataJson)) { LogUtil.w(TAG, "getHttpSuccessResponse: dataJson is empty!"); response = new Response.Builder() .code(500) .protocol(Protocol.HTTP_1_0) .request(request) //protocol&request be set,otherwise will be exception. .build(); } else { response = new Response.Builder() .code(200) .message(dataJson) .request(request) .protocol(Protocol.HTTP_1_0) .addHeader("Content-Type", "application/json") .body(ResponseBody.create(MediaType.parse("application/json"), dataJson)) .build(); } return response; } } 

6. Finally, you can request your server with the code:

 mHomeDataRequester.getEventList(new Subscriber<HttpResult<List<Event>>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { LogUtil.e(TAG, "onError: ", e); if (mView != null) { mView.onEventListLoadFailed(); } } @Override public void onNext(HttpResult<List<Event>> httpResult) { //Your json result will be convert by Gson and return in here!!! }); } 

Thanks for reading.

+7
Jul 29 '16 at 7:37
source share

Adding @Alec to the answer, I expanded the mock client to get the answer directly from the text file in the assets folder depending on the request URL.

Example

 @POST("/activate") public void activate(@Body Request reqdata, Callback callback); 

Here, the erroneous client understands that the activated URL is being activated and is looking for a file called activate.txt in the resource folder. It reads the contents from the assets / activate.txt file and sends it as an answer to the API.

Here is the advanced MockClient

 public class MockClient implements Client { Context context; MockClient(Context context) { this.context = context; } @Override public Response execute(Request request) throws IOException { Uri uri = Uri.parse(request.getUrl()); Log.d("MOCK SERVER", "fetching uri: " + uri.toString()); String filename = uri.getPath(); filename = filename.substring(filename.lastIndexOf('/') + 1).split("?")[0]; try { Thread.sleep(2500); } catch (InterruptedException e) { e.printStackTrace(); } InputStream is = context.getAssets().open(filename.toLowerCase() + ".txt"); int size = is.available(); byte[] buffer = new byte[size]; is.read(buffer); is.close(); String responseString = new String(buffer); return new Response(request.getUrl(), 200, "nothing", Collections.EMPTY_LIST, new TypedByteArray("application/json", responseString.getBytes())); } } 

For a detailed explanation, you can check your blog.
http://www.cumulations.com/blogs/13/Mock-API-response-in-Retrofit-using-custom-clients

+5
May 6 '15 at 12:12
source share

JSONPlaceholder: Fake Online REST API for testing and prototyping

https://jsonplaceholder.typicode.com/

ReqresIn: another online REST API

https://reqres.in/

Postman server layout

If you want to test a custom response payload, the two above may not meet your requirements, then you can try the server’s mail layout. It is quite easy to configure and flexibly define your own request and response payload.

enter image description here https://learning.getpostman.com/docs/postman/mock_servers/intro_to_mock_servers/ https://youtu.be/shYn3Ys3ygE

+1
Jul 17 '19 at 6:54
source share

For me, the custom Retrofit Client is distinguished by its flexibility. Especially when you use any DI wireframe, you can quickly and easily turn on / off the layout. I use the custom client provided by Dagger also in unit and integration tests.

Edit: Here you will find an example of a mocking upgrade https://github.com/pawelByszewski/retrofitmock

0
Feb 26 '14 at 1:19
source share

Remixing API calls with Retrofit is now even easier with Mockinizer , which makes working with MockWebServer very simple:

 import com.appham.mockinizer.RequestFilter import okhttp3.mockwebserver.MockResponse val mocks: Map<RequestFilter, MockResponse> = mapOf( RequestFilter("/mocked") to MockResponse().apply { setResponseCode(200) setBody("""{"title": "Banana Mock"}""") }, RequestFilter("/mockedError") to MockResponse().apply { setResponseCode(400) } ) 

Just create a RequestFilter and MockResponses map , and then insert it into the OkHttpClient linker chain:

 OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .mockinize(mocks) // <-- just plug in your custom mocks here .build() 

You do not need to worry about configuring MockWebServer, etc. Just add your layouts, Mockinizer will do the rest.

(Disclaimer: I'm the author of Mockinizer)

0
Aug 20 '19 at 19:30
source share



All Articles