테스트를위한 Square Retrofit 서버 모의
어떤 것은 사용하는 경우 테스트 서버 조롱하는 가장 좋은 방법 평방 개조 프레임 워크를 .
잠재적 인 방법 :
새 개조 클라이언트를 만들고 RestAdapter.Builder (). setClient ()에서 설정합니다. 여기에는 Request 객체를 구문 분석하고 json을 Response 객체로 반환하는 작업이 포함됩니다.
이 주석이 달린 인터페이스를 모의 클래스로 구현하고 RestAdapter.create ()에서 제공하는 버전 대신 사용합니다 (Want test gson serialization).
?
이상적으로는 mocked 서버가 json 응답을 제공하여 gson 직렬화를 동시에 테스트 할 수 있도록하고 싶습니다.
어떤 예라도 대단히 감사하겠습니다.
모의 Retrofit 2.0 테스트 요청
MockClient
클래스 생성 및 구현과 같은 이전 메커니즘 Client
이 더 이상 Retrofit 2.0에서 작동하지 않으므로 여기에서 새로운 방법을 설명합니다. 지금해야 할 일은 아래와 같이 OkHttpClient에 대한 사용자 정의 인터셉터 를 추가하는 것 입니다. FakeInterceptor
클래스는 intercept
메서드를 재정의 하고 응용 프로그램이 DEBUG
모드 에있는 경우 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 의 프로젝트 소스 코드
다음과 같이 방법 1을 시도하기로 결정했습니다.
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()));
}
}
그리고 그것을 사용하여 :
RestAdapter.Builder builder = new RestAdapter.Builder();
builder.setClient(new MockClient());
잘 작동하며 실제 서버에 접속하지 않고도 json 문자열을 테스트 할 수 있습니다!
객체에 대한 JSON 역 직렬화 테스트 (아마도 TypeAdapters
?를 사용하여)는 별도의 단위 테스트가 필요한 별도의 문제처럼 보입니다.
개인적으로 버전 2를 사용합니다. 쉽게 디버깅하고 변경할 수있는 형식 안전하고 리팩터링하기 쉬운 코드를 제공합니다. 결국, 테스트 용으로 대체 버전을 만들지 않는 경우 API를 인터페이스로 선언하는 것이 좋습니다! 승리를위한 다형성.
또 다른 옵션은 Java를 사용하는 것 Proxy
입니다. 이것은 실제로 Retrofit (현재)이 기본 HTTP 상호 작용을 구현하는 방법입니다. 이것은 분명히 더 많은 작업이 필요하지만 훨씬 더 역동적 인 모의를 허용합니다.
Squareup의 Webservermock과 같은 것을 사용할 수도 있습니다! -> https://github.com/square/okhttp/tree/master/mockwebserver
저는 실제 서버로 이동하기 전에 API를 조롱하는 Apiary.io 의 열렬한 팬입니다 .
플랫 .json 파일을 사용하여 파일 시스템에서 읽을 수도 있습니다.
Twitter, Flickr 등과 같이 공개적으로 액세스 할 수있는 API를 사용할 수도 있습니다.
다음은 Retrofit에 대한 다른 훌륭한 리소스입니다.
슬라이드 : https://docs.google.com/presentation/d/12Eb8OPI0PDisCjWne9-0qlXvp_-R4HmqVCjigOIgwfY/edit#slide=id.p
동영상 : http://www.youtube.com/watch?v=UtM06W51pPw&feature=g-user-u
예제 프로젝트 : https://github.com/dustin-graham/ucad_twitter_retrofit_sample
Mockery (면책 조항 : 저자입니다)는 정확히이 작업을 위해 설계되었습니다.
Mockery는 Retrofit에 대한 지원이 내장 된 네트워킹 계층 검증에 초점을 맞춘 모의 / 테스트 라이브러리입니다. 지정된 API의 사양을 기반으로 JUnit 테스트를 자동 생성합니다. 아이디어는 테스트를 수동으로 작성할 필요가 없습니다. 모의 서버 응답을위한 인터페이스를 구현하지 않습니다.
먼저 Retrofit 인터페이스를 만듭니다.
public interface LifeKitServerService { /** * query event list from server,convert Retrofit's Call to RxJava's 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(); }
귀하의 요청자는 다음과 같습니다.
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); } }
두 번째 선택 (Mock 서버 데이터에 Retrofit 인터페이스 사용)을 사용하는 경우 MockRetrofit이 필요합니다.
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. 내 데이터는 자산 파일 (Asset / server / EventList.json)에서 가져온 것입니다.이 파일 내용은 다음과 같습니다.
{
"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. okhttp3 인터셉터를 사용하는 경우 다음과 같이 자체 정의 된 인터셉터가 필요합니다.
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. 마지막으로 코드를 사용하여 서버를 요청할 수 있습니다.
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!!!
});
}
읽어 주셔서 감사합니다.
@Alec의 답변에 추가하여 요청 URL에 따라 자산 폴더의 텍스트 파일에서 직접 응답을 받도록 모의 클라이언트를 확장했습니다.
전의
@POST("/activate")
public void activate(@Body Request reqdata, Callback callback);
여기에서 모의 클라이언트는 실행되는 URL이 활성화되었음을 이해하고 자산 폴더에서 activate.txt라는 파일을 찾습니다. assets / activate.txt 파일에서 콘텐츠를 읽고 API에 대한 응답으로 보냅니다.
여기에 확장 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 checkout my blog
http://www.cumulations.com/blogs/13/Mock-API-response-in-Retrofit-using-custom-clients
JSONPlaceholder: Fake Online REST API for Testing and Prototyping
https://jsonplaceholder.typicode.com/
ReqresIn: Another Online REST API
Postman mock server
If you want to test customized response payload, the above two might not suit your requirement, then you can try postman mock server. It's quite easy to set up and flexible to define your own request and response payload.
https://learning.getpostman.com/docs/postman/mock_servers/intro_to_mock_servers/ https://youtu.be/shYn3Ys3ygE
For me the custom Retrofit Client is great because of flexibility. Especially when you use any DI framework you can fast and simple turn on/off mock. I am using custom Client provided by Dagger also in unit and integration tests.
Edit: Here you find example of mocking retrofit https://github.com/pawelByszewski/retrofitmock
Mocking api calls with Retrofit is now even easier with Mockinizer which makes working with MockWebServer really straight forward:
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 map of RequestFilter and MockResponses and then plug it into your OkHttpClient builder chain:
OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.mockinize(mocks) // <-- just plug in your custom mocks here
.build()
You don't have to worry about configuring MockWebServer etc. Just add your mocks all the rest is done by Mockinizer for you.
(Disclaimer: I am the author of Mockinizer)
참고URL : https://stackoverflow.com/questions/17544751/square-retrofit-server-mock-for-testing
'IT story' 카테고리의 다른 글
PostgreSQL ROLE (사용자)가없는 경우 생성 (0) | 2020.09.08 |
---|---|
숭고한 텍스트 2에서 코드 제외 섹션 접기 / 축소 (0) | 2020.09.08 |
MVC4 HTTP 오류 403.14-금지됨 (0) | 2020.09.08 |
jQuery select2 선택 태그의 값을 얻습니까? (0) | 2020.09.08 |
FTP를 통해 Azure 웹 사이트에 연결 (0) | 2020.09.08 |